.TITLE IOSUB .IDENT /17.15/ ; ; Copyright (c) 1995-1999 by Mentec, Inc., U.S.A. ; All rights reserved. ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; D. N. CUTLER 4-AUG-73 ; ; ; PREVIOUSLY MODIFIED BY: ; ; S. C. ADAMS ; J. W. BERZLE ; H. HUANG ; J. R. KAUFFMAN ; J. M. LAWLER ; T. LEKAS ; B. S. MCCARTHY ; L. B. MCCULLEY ; J. J. MELVIN ; K. L. NOEL ; M. PETTENGILL ; P. K. M. WEISS ; D. CARROLL ; ; MODIFIED FOR RSX-11M-PLUS V4.5 BY: ; ; ; D. Carroll 15-Feb-1993 17.11 ; DC125 -- Insure shadow failures do not fail over while ; performing an "UPDATE" operation on the index/ ; bitmap in $IOFIN, as an ACP I/O request may ; receive header/bitmap data from an inaccurate ; copy on the secondary volume. ; ; D. Carroll 05-May-1993 17.12 ; DC204 -- Don't tally internal IOC completion against total ; IOCs with extended accounting ; ; D. Carroll 15-Jun-1993 17.13 ; DC226 -- Honor MF.DSE when logging packets to SHE... ; and allow a MERGE COPY when processing IO.SCF ; ; Modified for RSX-11M-PLUS V4.6 by: ; ; D. Carroll 18-Oct-1995 17.14 ; DC404 - Include PSECT definition to allow ICB pool to be ; fully expanded on I/D space systems ; ; D. Carroll 26-Mar-1996 17.15 ; DC437 - Include support for ACP tasks to be I/D space ; ; ; I/O RELATED ROUTINES ; ; PRIMITIVE LEVEL ROUTINES CALLED BY MOST DRIVERS ; ; MACRO LIBRARY CALLS ; .MCALL F11DF$,HDRDF$,HWDDF$,PCBDF$,PKTDF$,SHDDF$,TCBDF$ .MCALL UCBDF$,SCBDF$,BGCK$A ; F11DF$ ;DEFINE WINDOW AND LOCK BLOCK OFFSETS HDRDF$ ;DEFINE TASK HEADER OFFSETS HWDDF$ ;DEFINE HARDWARE REGISTERS PCBDF$ ;DEFINE PARTITION CONTROL BLOCK OFFSETS PKTDF$ ;DEFINE I/O PACKET OFFSETS SHDDF$ ;DEFINE SHADOW RECORDING OFFSETS TCBDF$ ;DEFINE TASK CONTROL BLOCK OFFSETS SCBDF$ ;DEFINE STATUS CONTROL BLOCK OFFSETS UCBDF$ ;DEFINE UNIT CONTROL BLOCK OFFSETS .IIF DF,K$$DAS&I$$CBP, .PSECT EXEC1 ;DC404 ;DC404 ;+ ; **-$DECIO-DECREMENT I/O COUNT (THROUGH AN ATTACHMENT DESCRIPTOR) ; **-$DECIP-DECREMENT I/O COUNT (PARTITION ONLY) ; ; THESE ROUTINES DECREMENT THE I/O COUNT THROUGH AN ATTACHMENT ; DESCRIPTOR AND/OR ASSOCIATED PCB AND CHECK FOR ANY PENDING ; CHECKPOINT REQUESTS. ; ; INPUTS: ; ; R0=ADDRESS OF THE ATTACHMENT DESCRIPTOR. ; ; IF THE LOW BIT OF THE ADB ADDRESS IS SET, THEN ; THIS IS THE COMPLETION OF A BUFFERED I/O FOR ; WHICH THE PCB I/O COUNT HAS ALREADY BEEN DEC'D ; (VIA $DECBF). ONLY THE ADB I/O COUNT IS CHANGED. ; ; OUTPUTS: ; ; NONE. ; ; R3 IS PRESERVED, ALL OTHER REGISTERS CLOBBERED ; ;- .ENABL LSB $DECIO::BIT #1,R0 ;COMPLETION OF BUFFERED I/O ? BNE 60$ ;IF NE YES, GO DEC A.IOC AND RETURN DECB A.IOC(R0) ;REDUCE I/O COUNT THROUGH DESCRIPTOR $DECIP::MOV A.PCB(R0),R1 ;POINT TO THE REGION PCB DECB P.IOC(R1) ;REDDUCE COUNT OF I/O INTO PARTITION BNE 50$ ;IF NE THERE IS STILL I/O BIT #PS.CKR!PS.LIO,P.STAT(R1) ;CKP REQ OR SHF DETECTED I/O? BEQ 50$ ;IF EQ NO MOV R3,-(SP) ;SAVE I/O PACKET ADDRESS MOV #$ICHKP,-(SP) ;ASSUME ITS A CHECKPOINT REQUEST BIT #PS.CKR,P.STAT(R1) ;IS IT? BNE 10$ ;IF NE YES MOV #$NXTSK,(SP) ;MUST BE A SHUFFLER DETECTED LONG I/O MOV R1,R0 ;COPY PCB ADDRESS 10$: BIC #PS.CKR!PS.LIO,P.STAT(R1) ;CLEAR THE BITS CALL @(SP)+ ;CALL ROUTINE AND CLEAN STACK MOV (SP)+,R3 ;RESTORE I/O PACKET ADDRESS 50$: RETURN ; 60$: DECB A.IOC-1(R0) ;DECREMENT I/O COUNT THROUGH ATT. RETURN ; .DSABL LSB ;+ ; **-$ULDRQ-REQUEST MICROCODE LOADER ; ; THIS ROUTINE IS CALLED FROM A DRIVER TO REQUEST THE MICRO CODE LOADER ; TASK. A PACKET IS ALLOCATED AND THE LOAD INFO. IS INSERTED, THE PACKET ; IS QUEUED TO THE MICRO CODE LOADER AND THE MICRO CODE LOADER IS REQUESTED. ; ; INPUTS: ; ; R3=MICRO CODE FILENAME INDEX ; R4=KRB ADDRESS OF CONTROLLER FOR MICROCODE LOAD ; ; OUTPUTS: ; ; C=0 IF THE PACKET WAS ALLOCATED AND THE TASK INSTALLED. ; C=1 IF THE PACKET WAS NOT SUCCESSFULLY QUEUED ; Z=1 IF THE PACKET COULD NOT BE ALLOCATED ; Z=0 IF THE TASK WAS NOT INSTALLED ;- .ENABL LSB $ULDRQ::MOV #$ULDPT,-(SP) ;PUSH ADDRESS OF ADDRESS OF TCB BR 10$ ;AND ENTER COMMON PACKET ROUTINE ;+ ; **-$DVMSG-DEVICE MESSAGE OUTPUT ; ; THIS ROUTINE IS CALLED TO SUBMIT A MESSAGE TO THE TASK TERMINATION ; NOTIFICATION TASK. MESSAGES ARE EITHER DEVICE RELATED OR A CHECKPOINT ; WRITE FAILURE FROM THE LOADER. ; ; INPUTS: ; ; R0=MESSAGE NUMBER. ; R5=ADDRESS OF THE UCB OR TCB THAT THE MESSAGE APPLIES TO. ; ; OUTPUTS: ; ; A FOUR WORD PACKET IS ALLOCATED, R0 AND R5 ARE STORED IN THE ; SECOND AND THIRD WORDS RESPECTIVELY, AND THE PACKET IS THREADED ; INTO THE TASK TERMINATION NOTIFICATION TASK MESSAGE QUEUE. ; ; NOTE: IF THE TASK TERMINATION NOTIFICATION TASK IS NOT INSTALLED ; OR NO STORAGE CAN BE OBTAINED, THEN THE MESSAGE REQUEST ; IS IGNORED. ;- $DVMSG::MOV R0,R3 ;SAVE MESSAGE NUMBER .IF DF R$$PRO TST $TKNPT ;IS TKTN INSTALLED? BEQ $CTMSG ;IF EQ NO - TRY SENDING TO THE DISPATCHER .ENDC ;R$$PRO MOV #$TKNPT,-(SP) ;PUSH ADDRESS OF ADDRESS OF TKTN TCB BR 10$ ;DROP THROUGH TO COMMON QUEUE ROUTINE ;+ ; **-$QPKRQ-QUEUE PACKET AND REQUEST TASK ; ; THIS ROUTINE ATTEMPTS TO ALLOCATE A FOUR WORD BLOCK, SAVE R3-R5 IN ; THE BLOCK, AND QUEUE IT TO A SPECIFIED TASK. THE CONTENT OF THE ; BLOCK IS: ; WD 0 - LINK WORD FOR RECEIVE QUEUE ; WD 1 - SAVED R3 ; WD 2 - SAVED R5 ; WD 3 - SAVED R4 ; ; INPUTS: ; ; R0=ADDRESS OF ADDRESS OF TCB OF TASK TO REQUEST ; R3-R5=REGISTERS TO BE STORED ; ; OUTPUTS: ; ; C=0 IF ALLOCATION SUCCESSFUL AND TASK INSTALLED ; C=1 IF EITHER FAILED ; Z=1 IF PACKET NOT ALLOCATED ; Z=0 IF TASK NOT INSTALLED ;- $QPKRQ::MOV R0,-(SP) ;SAVE ADDRESS OF ADDRESS FOR COMMON CODE 10$: TST @(SP) ;SPECIFIED TASK INSTALLED BEQ 60$ ;IF EQ NO - ERROR MOV #8.,R1 ;SET LENGTH OF BLOCK NEEDED CALL $ALOCB ;GET A CORE BLOCK BCC 20$ ;FINISH IN COMMON ROUTINE BR 50$ ;IF CS DIDN'T GET PACKET ;+ ; **-$DVMG1-DEVICE MESSAGE OUTPUT (ALTERNATE ENTRY) ; **-$QPKR1-GENERAL QUEUEING ROUTINE (ALTERNATE ENTRY) ; ; THESE ROUTINES ARE CALLED IF A PACKET IS TO BE QUEUED WHICH IS ; ALREADY ALLOCATED (E.G. CONVERTING A KERNEL AST TO A DEVICE ; MESSAGE. THE PACKET MUST BE EXACTLY 8. BYTES LONG, AND IT IS ; THE DRIVERS RESPONSIBILITY TO INSURE THAT THE REQUESTED TASK ; IS INSTALLED. ; ; INPUTS: ; R0=ADDRESS OF THE PRE-ALLOCATED MESSAGE PACKET ; R3=MESSAGE NUMBER (OR EQUIVALENT) ; R2=ADDRESS OF ADDRESS OF TCB OF TASK (IF ENTRY AT $QPKR1) ; ; OUTPUTS: ; THE PACKET IS FILLED IN AND QUEUED TO THE SPECIFIED TASK ;- $DVMG1::MOV #$TKNPT,R2 ;PUSH ADDRESS OF TKTN TCB ADDRESS $QPKR1::MOV R2,-(SP) ;SAVE ADDRESS OF ADDRESS OF TCB 20$: MOV R0,R1 ;SET ADDRESS OF MESSAGE BLOCK TST (R0)+ ;POINT TO SECOND WORD IN BLOCK MOV R3,(R0)+ ;INSERT MESSAGE NUMBER MOV R5,(R0)+ ;INSERT UCB OR TCB ADDRESS MOV R4,(R0) ;INSERT ADDITIONAL PARAMETER MOV @(SP)+,R0 ;GET TCB ADDRESS OF TASK TO REQUEST CALL $EXRQF ;INSERT IN RECEIVE LIST, REQUEST CLC ;INDICATE SUCCESS RETURN ;BACK TO CALLER 50$: CLR (SP) ;SET TO SET Z BIT FOR RETURN 60$: COM (SP)+ ;CLEAN STACK, SET C AND Z IF APPROP. RETURN ;BACK TO CALLER .IF DF R$$PRO ;+ ; **-$CTMSG-DO A SEND DATA TO THE P/OS DISPATCHER ; ; THIS ROUTINE IS CALLED TO SEND A MESSAGE TO THE P/OS DISPATCHER BY ; DOING A SEND DATA. FOR NOW MESSAGES ARE FOR CHECKPOINT WRITE ERROR ; OR CHECKPOINT ALLOCATION FAILURE. ; ; INPUTS: ; ; R0=MESSAGE NUMBER ; ; OUPUTS: ; ; A FIXED LENGTH SEND DATA IS DONE TO C$CTEX IF POSSIBLE. ;- $CTMSG::MOV KISAR6,-(SP) ;SAVE THE APR6 MAPPING MOV R0,-(SP) ;SAVE THE MESSAGE NUMBER MOV #$CTBNM,R3 ;GET THE ADDRESS OF THE CTAB'S NAME (C$CTEX) CALL $SRSTD ;GET IT'S TCB ADDRESS BCS 95$ ;IF CS NOT INSTALLED - DROP THE MESSAGE MOV R0,-(SP) ;SAVE THE TCB ADDRESS MOV #<13.+8.+37>/32.,R1 ;GET A PACKET FOR A FIXED LENGTH SEND DATA CALL $ALSEC ;ALLOCATE THE PACKET BCS 90$ ;IF CS NO SPACE - DROP THE MESSAGE MOV R0,KISAR6 ;MAP THE PACKET MOV #140002,R0 ;POINT AFTER THE LINK WORD IN THE PACKET MOV #13.+2,(R0)+ ;INSERT THE NUMBER OF DATA WORDS MOV #^R$$E,(R0)+ ;INSERT THE SENDER "TASK" NAME - $$EXEC MOV #^RXEC,(R0)+ ;... MOV #4,(R0)+ ;INSERT THE MESSAGE TYPE (EXEC MESSAGE) MOV 2(SP),(R0)+ ;GET THE SUBMESSAGE NUMBER ADD #<13.-2>*2,R0 ;POINT PAST THE DATA AREA MOV $COPT,(R0)+ ;TI: FOR THIS "TASK" IS CO0: MOV #<200*400>+200,(R0)+ ;THE UIC FOR P/OS SHOULD ALWAYS BE 200,200 MOV $CTBNM,(R0)+ ;INSERT THE TARGET TASK NAME MOV $CTBNM+2,(R0) ;... MOV (SP),R0 ;GET THE ADDRESS OF RECIEVER TASK'S TCB ADD #T.RCVL,R0 ;POINT TO THE RECIEVE LIST MOV KISAR6,R1 ;GET ADDRESS OF THE PACKET CALL $QSPIF ;INSERT PACKET IN THE RECIEVE LIST MOV #AS.RCA,R4 ;GET CODE FOR RECIEVE DATA AST MOV (SP)+,R5 ;RETRIEVE RECIEVER TASK'S TCB ADDRESS TST (SP)+ ;DON'T NEED THE MESSAGE NUMBER ANYMORE MOV (SP)+,KISAR6 ;RESTORE THE APR6 MAPPING CALL $DASTT ;DECLARE RECIEVE AST CALLR $DRDSE ;DECLARE A SIGNIFICANT EVENT 90$: TST (SP)+ ;CLEAN THE STACK 95$: TST (SP)+ ;CLEAN THE STACK 100$: MOV (SP)+,KISAR6 ;RESTORE THE APR6 MAPPING RETURN ;ALL DONE .ENDC ;R$$PRO .DSABL LSB ;+ ; **-$GTPKT-GET I/O PACKET FROM REQUEST QUEUE ; **-$GSPKT-GET SELECTIVE I/O PACKET FROM REQUEST QUEUE ; ; THIS ROUTINE IS CALLED BY DEVICE DRIVERS TO DEQUEUE THE NEXT I/O REQUEST TO ; PROCESS. IF THE DEVICE CONTROLLER IS BUSY, THEN A CARRY SET INDICATION IS ; RETURNED TO THE CALLER. ELSE AN ATTEMPT IS MADE TO DEQUEUE THE NEXT REQUEST ; FROM THE CONTROLLER QUEUE. IF NO REQUEST CAN BE DEQUEUED, THEN A CARRY ; SET INDICATION IS RETURNED TO THE CALLER. ELSE THE CONTROLLER IS SET BUSY AND ; A CARRY CLEAR INDICATION IS RETURNED TO THE CALLER. ; ; IF QUEUE OPTIMIZATION IS SUPPORTED AND ENABLED FOR THE DEVICE ; THE APROPRIATE PACKET FOR THE CURRENT OPTIMIZATION ALGORITHM ; IS RETURNED. THREE ALGORITHMS ARE SUPPORTED: NEAREST CYLINDER, ; ELEVATOR, AND C-SCAN. ALL THREE ALGORITHMS INCORPORATE A ; FAIRNESS COUNT. IF THE FIRST PACKET ON THE LIST IS PASSED OVER ; MORE THAN "FCOUNT" TIMES, IT IS DONE IMMEDIATELY. ; ; ; THE ALTERNATE ENTRY POINT $GSPKT IS INTENDED FOR USE BY DRIVERS WHICH ; SUPPORT PARALLEL OPERATIONS ON A SINGLE UNIT, A COMMON EXAMPLE BEING ; FULL DUPLEX. SUCH DRIVERS ARE EXPECTED TO LOOK TO THE SYSTEM AS IF ; THEY ARE ALWAYS FREE, WHILE MAINTAINING THE STATUS OF ALL PARALLEL ; OPERATIONS INTERNALLY WITHIN THEIR OWN DEVICE DATA STRUCTURES. ; PARALLELISM IS ACCOMPLISHED BY HANDLING DRIVER-DEFINED CLASSES OF I/O ; FUNCTION CODES IN PARALLEL WITH EACH OTHER. FOR EXAMPLE A FULL-DUPLEX ; DRIVER WOULD HANDLE INPUT REQUESTS IN PARALLEL WITH OUTPUT REQUESTS. ; A DRIVER CALLS $GSPKT WHEN IT WANTS TO DEQUEUE A PACKET WHOSE I/O ; FUNCTION CODE BELONGS TO A CERTAIN CLASS. WHICH FUNCTIONS QUALIFY IS ; DETERMINED BY AN ACCEPTANCE ROUTINE IN THE DRIVER WHOSE ADDRESS IS ; PASSED TO $GSPKT IN R2. THE ACCEPTANCE ROUTINE IS CALLED BY $GSPKT ; EACH TIME A PACKET IS FOUND IN THE QUEUE WHICH IS ELIGIBLE TO BE ; DEQUEUED. THE ACCEPTANCE ROUTINE IS THEN EXPECTED TO TAKE ONE OF THE ; FOLLOWING THREE ACTIONS: ; ; 1. RETURN WITH CARRY CLEAR IF THE PACKET SHOULD BE ; DEQUEUED. IN THIS CASE $GSPKT PROCEEDS AS $GTPKT ; NORMALLY WOULD ON DEQUEUEING THE PACKET. ; ; 2. RETURN WITH CARRY SET IF THE PACKET SHOULD NOT BE ; DEQUEUED. IN THIS CASE $GSPKT WILL CONTINUE THE SCAN ; OF THE I/O QUEUE. ; ; 3. ADD THE CONSTANT G$$SPSA TO THE STACK POINTER TO ABORT ; THE SCAN WITH NO FURTHER ACTION. ; ; THE ACCEPTANCE ROUTINE MUST SAVE AND RESTORE ANY REGISTERS WHICH IT ; INTENDS TO MODIFY. WHEN A PACKET IS DEQUEUED VIA $GSPKT, THE ; FOLLOWING NORMAL $GTPKT ACTIONS DO NOT OCCUR: ; ; 1. FILLING IN OF U.BUF, U.BUF+2 AND U.CNT. THESE FIELDS ; ARE AVAILABLE FOR DRIVER-SPECIFIC USE. ; ; 2. BUSYING OF UCB AND SCB. ; ; 3. EXECUTION OF $CFORK TO GET TO PROPER PROCESSOR (MULTI- ; PROCESSOR SYSTEMS). ; ; NOTE: $GSPKT MAY NOT BE USED BY A DRIVER WHICH SUPPORTS ; QUEUE OPTIMIZATION. ; ; ; INPUTS: ; ; R2=ADDRESS OF DRIVER'S ACCEPTANCE ROUTINE (IF CALL AT $GSPKT). ; R5=ADDRESS OF THE UCB OF THE CONTROLLER TO GET A PACKET FOR. ; ; OUTPUTS: ; ; C=1 IF CONTROLLER IS BUSY OR NO REQUEST CAN BE DEQUEUED. ; C=0 IF A REQUEST WAS SUCCESSFULLY DEQUEUED. ; R1=ADDRESS OF THE I/O PACKET. ; R2=PHYSICAL UNIT NUMBER. ; R3=CONTROLLER INDEX. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UNIT CONTROL BLOCK. ; ; NOTE: R4 AND R5 ARE DESTROYED BY THIS ROUTINE. ;- ; ; DEFINE ADDRESS IN THE UCB EXTENSION AS MAPPED THRU APR6 ; IOC=X.IOC+140000 ;I/O COUNT WCNT=X.WCNT+140000 ;WORDS TRANSFERED COUNT CYLC=X.CYLC+140000 ;CYLINDERS CROSSED COUNT CCYL=X.CCYL+140000 ;CURRENT CYLINDER FCUR=X.FCUR+140000 ;CURRENT FAIRNESS COUNT FLIM=X.FLIM+140000 ;FAIRNESS COUNT LIMIT DSKD=X.DSKD+140000 ;DISK DIRECTION (1=OUT) ; ********************************************************* ; * * ; * > > > W A R N I N G < < < * ; * * ; * THE FOLLOWING ARE OFFSET DEFINITIONS WHICH ARE * ; * SUPPLIED EITHER BY DEFINITION IN THE EXEC (IOSUB) * ; * OR THE DUMMY STB FILE (FROM SFVC2). ANY CHANGE TO * ; * THESE DEFINITIONS MUST BE MADE IN BOTH MODULES. * ; * * ; ********************************************************* ; TEMP=26 ;AMOUNT OF TEMPORARY STORAGE REQUIRED G$$SPA==TEMP+6 ;CONSTANT TO ADD TO SP TO ABORT SCAN .ENABL LSB $GTPKT::MOV #128$,R2 ;ACCEPT ALL PACKETS $GSPKT::MOV R2,$TEMP2 ;SAVE ADDRESS OF ACCEPTANCE ROUTINE 5$: SUB #TEMP,SP ;GET TEMPORARY STORAGE ON STACK 10$: MOV U.SCB(R5),R4 ;GET ADDRESS OF STATUS CONTROL BLOCK TSTB S.STS(R4) ;CONTROLLER BUSY? BNE 20$ ;IF NE CONTROLLER IS BUSY BIC #S2.EIP,S.ST2(R4) ;CLEAR ERROR IN PROGRESS MOV R4,R1 ;GET THE ADDRESS OF THE LISTHEAD 15$: CALL SCAN ;SCAN FOR A USABLE PACKET BCS 20$ ;NO MORE PACKETS CALL ACPCHK ;ACP FUNCTION? BCC 25$ ;IF CC NO CALL DEQUE ;REMOVE THE PACKET ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER 22. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPH22==. ;SPM CHANGES THE INSTRUCTION AT ;THE LOCATION OF THIS LABEL MOV U.ACP(R5),R0 ;GET ADDRESS OF ACP TCB CALL $EXRQP ;INSURE FILE SYSTEM IS ACTIVE BR 10$ ;GO AGAIN 20$: JMP 95$ ;EXIT 25$: ; ; IN REMOTE SYSTEMS, THE GENERIC DRIVER WILL HANDLE THE ATTACH AND DETATCH ; REQUESTS FOR THE REMOTE DEVICES ; .IF DF C$$RMT ;REMOTE HOST SUPPORT BIT #HF.RMT,$HFMSK ;REOMTE HOST SUPPROT ENABLED? BEQ 27$ ;IF EQ NO MOV I.UCB(R1),R2 ;GET UCB ADDRESS CMP (R2),$XXLOW ;IS THE DCB ADDRESS IN THE GENERIC RANGE? BLO 27$ ;IF LO NO CMP (R2),$XXHGH ;IS IT? BLOS 60$ ;IF LO OR SAME, YES 27$: .ENDC ; C$$RMT ; ; PROCESS ATTACH/DETACH ; MOVB I.FCN+1(R1),R2 ;GET I/O FUNCTION CODE CMPB #IO.ATT/256.,R2 ;ATTACH FUNCTION? BNE 45$ ;IF NE NO CALL DEQUE ;REMOVE THE PACKET MOV #IE.PRI&377,R0 ;ASSUME PRIVILEGE VIOLATION TST U.CW1(R5) ;MOUNTABLE DEVICE? BPL 30$ ;IF PL NO BITB #US.MNT!US.FOR,U.STS(R5) ;NOT MOUNTED OR FOREIGN? BEQ 55$ ;IF EQ NO 30$: MOV I.TCB(R1),R0 ;ASSUME SUCCESSFUL ATTACH TST U.ATT(R5) ;UNIT ALREADY ATTACHED? BEQ 35$ ;IF EQ NO MOV #IE.DAA&377,R0 ;SET STATUS OF DEVICE ALREADY ATTACHED BR 55$ ; 35$: BITB #IQ.UMD,I.FCN(R1) ;IS THIS A DIAGNOSTIC ATTACH? BEQ 50$ ;IF EQ NO BIT #DV.UMD,U.CW1(R5) ;USER MODE DIAGNOSTICS SUPPORTED? BEQ 40$ ;IF EQ NO BISB #US.UMD,U.ST2(R5) ;INDICATE DIAGNOSTIC ATTACH BR 50$ ; 40$: MOV #IE.IFC&377,R0 ;SET STATUS OF ILLEGAL FUNCTION BR 55$ ; 45$: CMPB #IO.DET/256.,R2 ;DETACH FUNCTION BNE 60$ ;IF NE NO CALL DEQUE ;REMOVE THE PACKET MOV #IE.DNA&377,R0 ;ASSUME DEVICE NOT ATTCHED TST R3 ;UNIT ATTACHED? BEQ 55$ ;IF EQ NO CLR R0 ;SET TO DETACH UNIT BICB #US.UMD,U.ST2(R5) ;RESET DIAGNOSTIC BIT 50$: MOV R0,U.ATT(R5) ;ATTACH/DETACH UNIT BITB #UC.ATT,U.CTL(R5) ;DOES DRIVER WANT CONTROL ON ATT/DET? BNE 56$ ;IF NE YES MOV #IS.SUC&377,R0 ;SET SUCCESSFUL COMPLETION STATUS 55$: ADD #TEMP,SP ;CLEANUP THE STACK FOR $IOALT CLR R1 ;ZERO SECOND I/O STATUS WORD MOV U.SCB(R5),R4 ;GET ADDRESS OF STATUS CONTROL BLOCK BICB #US.BSY,U.STS(R5) ;CLEAR UNIT BUSY CLRB S.STS(R4) ;CLEAR CONTROLLER BUSY CALL $IOAL2 ;FINISH I/O OPERATION BR 5$ ;GO AGAIN 56$: JMP 120$ ;PASS THE BRANCH ON 60$: BIT #DV.MSD,U.CW1(R5) ;IS THIS A MASS STORAGE DEVICE? BEQ 111$ ;IF EQ, NO, CAN'T DO OPT OR STATS .IF DF R$$AMD ;AUTOMATIC MOUNT/DISMOUNT ASSUME US.SIO,200 TSTB U.ST2(R5) ;STALLED I/O FOR THIS UNIT ? BMI 111$ ;IF MI, YES. NO OPT OR STATS .ENDC ; DF R$$AMD MOV KISAR6,$TONYL ;SAVE DATA SPACE APR6 MOV U.UCBX(R5),KISAR6 ;MAP UCB EXTENSION BEQ 110$ ;IF EQ, NO UCB EXT, CAN'T DO OPT OR STATS BITB #S3.OPT,S.ST3(R4) ;SEEK OPTIMIZATION ENABLED? BEQ 105$ ;IF EQ NO, DO STATS ONLY ; ; INITIALIZATION FOR THE QUEUE OPTIMIZATION SCAN LOOP ; TST (R1) ;IS THIS THE ONLY PACKET? BEQ 104$ ;IF EQ YES - DO IT NOW INCB FCUR ;INCREMENT THE FAIRNESS COUNT MOVB FLIM,R2 ;GET THE MAX COUNT BICB #200,R2 ;CLEAR THE DIRECTION BIT CMPB R2,FCUR ;FAIRNESS COUNT EXPIRED? BLO 104$ ;IF LO YES - DO IT NOW ; ; TWO IS SUBTRACTED FROM THE OFFSETS BELOW BECAUSE THE STACK ; DOES NOT HAVE THE QUEUE SCAN LOOP RETURN ADDRESS ON IT ; ASSUME OUTEX-2 ;ASSUME OUTEX-2 = 0 75$: CLR (SP) ;CLEAR THE EXISTANCE INDICATORS MOV R1,LOWPK-2(SP) ;INIT ADDRESS OF LOWEST PACKET MOV R0,LOWPR-2(SP) ;INIT ADDRESS OF LOWEST PACKET MOV I.PRM+10(R1),LOW-2(SP) ;INIT LOWEST CYLINDER # MOVB I.PRI(R1),PRI-2(SP) ;INIT PRIORITY ; ; QUEUE OPTIMIZATION SCAN LOOP ; 80$: CALL QOPUPD ;UPDATE THE QUEUE OPT INFO BCS 105$ ;IF CS DO THIS PACKET NOW! 85$: CALL SCAN ;SCAN FOR THE NEXT USABLE PACKET BCS 100$ ;IF CS THERE ARE NO MORE CMPB I.PRI(R1),PRI-2(SP) ;SAME PRIORITY? BNE 100$ ;IF NE NO - GO PICK A PACKET 90$: CMPB #IO.ATT/256.,I.FCN+1(R1) ;ATTACH? BEQ 85$ ;IF EQ YES - GO ON CMPB #IO.DET/256.,I.FCN+1(R1) ;DETACH? BEQ 85$ ;IF EQ YES - GO ON BITB #IQ.UMD,I.FCN(R1) ;IS THIS A DIAGNOSTIC FUNCTION? BNE 85$ ;IF NE YES - GO ON BR 80$ ;CONSIDER THIS ONE 95$: ADD #TEMP,SP ;RETURN THE TEMPORARY STORAGE SEC ;SET CARRY FOR NO PACKET JMP 130$ ;AND EXIT 100$: CALL FNDOPT ;FIND THE OPTIMAL PACKET CMP R1,(R4) ;IS THIS THE FIRST PACKET? BNE 105$ ;IF NE NO - GO ON 104$: CLRB FCUR ;CLEAR THE FAIRNESS COUNT 105$: ADD #1,IOC ;UPDATE UNIT I/O COUNT ADC IOC+2 ;AND THE HIGH ORDER WORD CMPB #IO.RLB/256.,I.FCN+1(R1) ;LOGICAL TRANSFER FUNCTION? BLO 110$ ;IF LO NO MOV I.PRM+4(R1),R3 ;GET THE BYTE COUNT ;+ ; Note: The following instruction counts on the fact that the ; compare immediately preceding this comment will branch ; if the result is CS. ;- ROR R3 ; MAKE IT WORDS, AND DON'T PROPOGATE SIGN ADD R3,WCNT ;UPDATE TOTAL WORDS XFERED COUNT ADC WCNT+2 ;AND THE HIGH ORDER WORD BIT #S2.OPT,S.ST2(R4) ;QUEUE OPT SUPPORTED? BEQ 110$ ;IF EQ NO MOV CCYL,R3 ;GET THE OLD CYLINDER NUMBER MOV I.PRM+10(R1),CCYL ;SET THE NEW CURRENT CYL SUB CCYL,R3 ;SUBTRACT CURRENT CYLINDER NUMBER BPL 108$ ;GET THE ABSOLUTE NEG R3 ;VALUE OF THE DIFFERENCE 108$: ADD R3,CYLC ;UPDATE THE CYLINDERS ADC CYLC+2 ;THE SECOND WORD 110$: MOV $TONYL,KISAR6 ;RESTORE DATA APR6 MAPPING 111$: CALL DEQUE ;REMOVE THE PACKET FOR PROCESSING 120$: ADD #TEMP,SP ;RETURN THE TEMPORARY STORAGE .IF DF S$$HDW BIT #DV.MSD,U.CW1(R5) ;IS THIS A MASS STORAGE DEVICE? BEQ 125$ ;IF EQ NO MOV R1,R3 ;COPY I/O PACKET ADDRESS FOR $SHFND CALL $SHFN1 ;SEE IF THIS UNIT IS SHADOWED NOW BCS 124$ ;IF CS NO CMP ML.PRI(R4),R1 ;IS THIS THE PRIMARY PACKET? BNE 124$ ;IF NE NO -- DON'T COPY MOV R1,-(SP) ;SAVE R1 (I/O PACKET ADDRESS) CMPB #IO.WLB/400,I.FCN+1(R2) ;IS IT A WRITE? BNE 123$ ;IF NE NO -- DON'T QUEUE IT NOW MOV R5,-(SP) ;SAVE UCB ADDRESS MOV U.SCB(R5),R4 ;GET SCB ADDRESS OF PRIMARY MOV R2,R1 ;COPY PKT ADDRESS MOV I.UCB(R1),R5 ;GET UCB ADDRESS OF SECONDARY DISK CLR -(SP) ;ASSUME PRIMARY AND SECONDARY ;HAVE SEPARATE SCBS CMP U.SCB(R5),R4 ;PRIMARY AND SECONDARY HAVE SAME SCB? BNE 121$ ;IF NE NO, OK CMP $TEMP2,#128$ ;$GSPKT CALL? BNE 121$ ;IF NE YES, OK WITH SAME SCB MOV R4,(SP) ;REMEMBER WE HAD TO INC S.STS INCB S.STS(R4) ;SHOW THIS SCB BUSY 121$: CALL $DRQRQ ;QUEUE I/O PACKET TO OTHER UNIT MOV (SP)+,R4 ;DID WE INCREMENT S.STS? BEQ 122$ ;IF EQ NO DECB S.STS(R4) ;PUT IT BACK 122$: MOV (SP)+,R5 ;RESTORE UCB ADDRESS OF PRIMARY 123$: MOV (SP)+,R1 ;RESTORE R1 (I/O PACKET ADDRESS) 124$: MOV U.SCB(R5),R4 ;RESTORE SCB ADDRESS MOV R1,S.PKT(R4) ;RE-SET I/O PACKET ADDRESS INTO SCB 125$: ;REF LABEL .ENDC CMP $TEMP2,#128$ ;$GSPKT CALL? BNE 127$ ;IF NE YES, SKIP TO DRIVER CALL MOV I.PRM(R1),U.BUF(R5) ;INSERT RELOCATION BIAS IN UCB MOV I.PRM+2(R1),U.BUF+2(R5) ;INSERT BUFFER ADDRESS IN UCB MOV I.PRM+4(R1),U.CNT(R5) ;INSERT BYTE COUNT IN UCB INCB S.STS(R4) ;SHOW CONTROLLER BUSY BISB #US.BSY,U.STS(R5) ;SHOW UNIT BUSY MOV S.KRB(R4),R3 ;GET KRB ADDRESS BEQ 126$ ;IF EQ NO KRB BIT #KS.UOP,K.STS(R3) ;IS CONTROLLER PARALLEL OPERATION ENB BEQ 126$ ;IF EQ NO ; ; CONTROLLER SUPPORTS PARALLEL OPERATION, AND REQUIRES SYNCHRONIZATION. ; THIS TYPE OF CONTROLLER USUALLY HAS THE INTERRUPT ENABLED, AND IS ; CAPABLE OF SUSTAINING AN INTERRUPT WHILE INITIATING A NEW FUNCTION. ; THE INTERRUPT MAY BE FROM SOME EXTERNAL EVENT, SUCH AS A DISK ; BECOMMING READY. IF LEFT ALONE, THE DRIVER WOULD AUTOMATICALLY FORK ; FOR EVERY INTERRUPT, WHICH WOULD NOT DO SINCE THE FORK BLOCK IS USED ; TO HOLD THE DRIVER CONTEXT FOR A NUMBER OF CONDITIONS DURING I/O ; INITIATION. THE PC WORD OF THE FORK BLOCK IS USED AS AN INTERLOCK ; TO SHOW IF A FORK IS ALLOWED, WHERE S.FRK+2 IS ZERO IF AN INTERRUPT ; IS ALLOWED. IT IS THE DRIVERS RESPONSIBILITY TO CLR S.FRK+2 TO ; ALLOW INTERRUPTS ONCE THEY ARE EXPECTED. THE ONLY OTHER PROBLEM ; OCCURS WHEN A DRIVER HAS QUEUED A FORK WHILE THE EXEC AND/OR DRIVER ; WERE ON THEIR WAY TO THIS POINT, AND WHEN $GTPKT ARRIVES HERE A ; FORK BLOCK IS CURRENTLY IN THE FORK QUEUE. THE SOLUTION FOR THIS ; IS TO SIMPLY DEQUEUE THE FORK BLOCK AND THEREBY DROP THE INTERRUPT ON ; THE FLOOR. WE WILL PROCEED TO DO THIS. ; MTPS #PR7 ;INHIBIT DEADLOCK LOCK$ $FORKL,SPIN INC S.FRK+2(R4) ;;;SHOW FORK BLOCK IN USE MOV #$FRKHD,R0 ;;;PREPARE TO REMOVE IT FROM QUEUE TST (R0) ;;;IS IT POSSIBLY THERE ? BEQ 1251$ ;;;IF EQ NO MOV R4,R1 ;;;COPY SCB ADDRESS ADD #S.FRK,R1 ;;;POINT TO FORK BLOCK CALL $QRMVA ;;;REMOVE IT FROM THE QUEUE 1251$: ;REFERENCE LABEL ULOCK$ $FORKL,SPIN MTPS #0 .IF DF M$$PRO BR 127$ ;REENTER FLOW .ENDC 126$: ;REFERENCE LABEL .IF DF M$$PRO MOV (SP)+,R4 ;SAVE RETURN ADDRESS CALL $CFORK ;EXECUTE ON CORRECT PROCESSOR MOV R4,-(SP) ;REPLACE RETURN ADDRESS MOV U.SCB(R5),R4 ;RETRIEVE SCB ADDRESS .ENDC 127$: ;REFERENCE LABEL MOV S.PKT(R4),R1 ;RETRIEVE I/O PACKET ADDRESS MOVB U.UNIT(R5),R2 ;SET PHYSICAL UNIT NUMBER ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER 17. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPH17==. ;SPM CHANGES THE INSTRUCTION AT ;THE LOCATION OF THIS LABEL MOV S.KRB(R4),R3 ;GET KRB ADDRESS BEQ 128$ ;IF EQ NO KRB MOVB K.CON(R3),R3 ;GET CONTROLLER INDEX 128$: CLC ;SHOW VALID I/O PACKET FOR RETURN 130$: ;REFERENCE LABEL ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER - THE FOLLOWING RETURN IS THE ; NULL CALL FOR HOOKING SEVERAL EXTERNAL TASKS. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPVEX==. ;SPM EXPECTS THIS INSTRUCTION ;TO BE RETURN RETURN .DSABL LSB ; ; QOPUPD -- UPDATE THE QUEUE OPTIMIZATION INFORMATION ; ; THIS ROUTINE UPDATES THE QUEUE OPTIMIZATION SCAN INFORMATION ; FOR THE CURRENT PACKET. THIS INFORMATION IS USED LATER BY FNDOPT. ; ; INPUT: ; ; R1=ADDRESS OF THE CURRENT I/O PACKET ; R5=ADDRESS OF THE UCB ; ; OUTPUTS: ; ; C=0 IF THE SCAN SHOULD CONTINUE. ; THE OPTIMIZATION DATA IS UPDATED. ; THIS DATA IS ON THE STACK IN THE FOLLOWING FORM. ; ; +--------------------------------------------+ ; 30(SP) ! DRIVER RETURN ADDRESS ! ; !--------------------------------------------! ; 26(SP) ! CURRENT PRIORITY ! ; !--------------------------------------------! ; 24(SP) ! LOWEST CYLINDER ! ; !--------------------------------------------! ; 22(SP) ! ADDRESS OF THE ABOVE PACKET ! ; !--------------------------------------------! ; 20(SP) ! ADDRESS OF THE PREVIOUS PACKET FOR ABOVE ! ; !--------------------------------------------! ; 16(SP) ! NEAREST CYLINDER IN THE INWARD DIRECTION ! ; !--------------------------------------------! ; 14(SP) ! ADDRESS OF THE ABOVE PACKET ! ; !--------------------------------------------! ; 12(SP) ! ADDRESS OF THE PREVIOUS PACKET FOR ABOVE ! ; !--------------------------------------------! ; 10(SP) ! NEAREST CYLINDER IN THE OUTWARD DIRECTION ! ; !--------------------------------------------! ; 6(SP) ! ADDRESS OF THE ABOVE PACKET ! ; !--------------------------------------------! ; 4(SP) ! ADDRESS OF THE PREVIOUS PACKET FOR ABOVE ! ; !--------------------+-----------------------! ; 3(SP) ! INWARD EXISTANCE ! OUTWARD EXISTANCE ! ; 2(SP) ! FLAG (HIGH BIT=1) ! FLAG (HIGH BIT=1) ! ; !--------------------+-----------------------! ; 0(SP) ! OPTIMIZATION LOOP RETURN ADDRESS ! ; +--------------------------------------------+ ; ; ALL REGISTERS ARE PRESERVED. ; ; ; C=1 IF THE CURRENT PACKET SHOULD BE USED ; R1=ADDRESS OF THE CURRENT PACKET ; R0-ADDRESS OF THE PREVIOUS PACKET ; ; ; NOTE: THESE OFFSETS ARE ALSO USED BY FNDOPT ; PKT=I.PRM+10 ;OFFSET (R1) FOR CYLINDER FOR THIS PACKET PRI=26 ;OFFSET (SP) FOR THE CURRENT PRIORITY LOW=24 ;OFFSET (SP) FOR LOWEST CYLINDER NUMBER LOWPK=22 ;OFFSET (SP) FOR PACKET ADDRESS OF LOW LOWPR=20 ;OFFSET (SP) FOR PREVIOUS PACKET ADDRESS FOR LOW OUT=10 ;OFFSET (SP) FOR NEAREST CYL IN THE OUTWARD DIR OUTPK=6 ;OFFSET (SP) FOR PACKET ADDRESS OF OUT OUTPR=4 ;OFFSET (SP) FOR PREVIOUS PACKET ADDRESS FOR OUT IN=16 ;OFFSET (SP) FOR NEAREST CYL IN THE INWARD DIR INPK=14 ;OFFSET (SP) FOR PACKET ADDRESS OF IN INPR=12 ;OFFSET (SP) FOR PREVIOUS PACKET ADDRESS FOR IN OUTEX=2 ;OFFSET (SP) FOR OUTWARD EXISTANCE INDICATOR INEX=3 ;OFFSET (SP) FOR INWARD EXISTANCE INDICATOR QOPUPD: CMP PKT(R1),CCYL ;ON CURRENT CYLINDER? BNE 10$ ;IF NE NO SEC ;EXIT WITH CARRY SET (DO IT NOW) BR 70$ ; 10$: CMP PKT(R1),LOW(SP) ;IS THIS THE CURRENT LOWEST? BHIS 20$ ;IF GE NO MOV PKT(R1),LOW(SP) ;SET THE NEW LOWEST CYLINDER NUMBER, MOV R1,LOWPK(SP) ;ITS PACKET ADDRESS, MOV R0,LOWPR(SP) ;AND THE PREVIOUS PACKET ADDRESS 20$: CMP PKT(R1),CCYL ;THIS PACKET LESS THAN CURRENT LOCATION? BLOS 40$ ;IF LE YES TSTB OUTEX(SP) ;HAVE WE SETUP OUTWARD YET? BPL 30$ ;IF PL NO CMP PKT(R1),OUT(SP) ;THIS PACKET NEAREST OUTWARD ONE? BHIS 60$ ;IF GE NO 30$: MOV PKT(R1),OUT(SP) ;SET THE NEW NEAREST OUTWARD CYL, MOV R1,OUTPK(SP) ;ITS PACKET ADDRESS, MOV R0,OUTPR(SP) ;AND THE PREVIOUS PACKET ADDRESS BISB #200,OUTEX(SP) ;AND NOTE IT BR 60$ ;EXIT 40$: TSTB INEX(SP) ;HAVE WE SETUP INWARD YET? BPL 50$ ;IF PL NO CMP PKT(R1),IN(SP) ;THIS PACKET NEAREST INWARD ONE? BLOS 60$ ;IF LE NO 50$: MOV PKT(R1),IN(SP) ;SET THE NEW NEAREST INWARD CYL, MOV R1,INPK(SP) ;ITS PACKET ADDRESS, MOV R0,INPR(SP) ;AND THE PREVIOUS PACKET ADDRESS BISB #200,INEX(SP) ;AND NOTE IT 60$: CLC ;SET FLAG FOR CONTINUED SCAN 70$: RETURN ; ; ; FNDOPT -- FIND THE OPTIMAL PACKET FOR THE CURRENT ALGORITHM ; ; THIS ROUTINE PICKS THE OPTIMAL PACKET USING THE DATA PRODUCED ; BY QOPUPD. IT SUPPORTS NEAREST CYLINDER, ELEVATOR, AND C-SCAN. ; ; NOTE: THE OFFSETS AND THE STACK STRUCTURE ARE DEFINED IN QOPUPD ; ; INPUTS: ; ; THE DATA PRODUCED BY QOPUPD. ; R4=SCB ADDRESS ; R5=UCB ADDRESS ; CCYL=CURRENT CYLINDER NUMBER ; DSKD=HIGH BIT OF BYTE SET IF MOVING OUTWARD ; ; THE OPTIMIZATION ALGORITHM ENCODED AS FOLLOWS: ; ; S2.OP2,S2.OP1=0,0 NEAREST CYLINDER ; =0,1 ELEVATOR ; =1,0 C-SCAN ; =1,1 RESERVED ; ; ; OUTPUT: ; ; R1=ADDRESS OF THE OPTIMAL PACKET ; THE CURRENT CYLINDER NUMBER IS UPDATED ; THE DIRECTION IS UPDATED IF NECESSARY ; ; FNDOPT: BIT #S2.OP2,S.ST2(R4) ;C-SCAN OR RESERVED? BEQ 20$ ;IF EQ NO BIT #S2.OP1,S.ST2(R4) ;RESERVED? BEQ 10$ ;IF EQ NO BGCK$A BF.OPT,BE.IDC,FATAL ;OPTIMIZATION - RESERVED CODE ; ; C-SCAN ; 10$: TSTB OUTEX(SP) ;OUTWARD PACKET EXIST? BMI 50$ ;IF MI YES - RETURN IT MOV LOWPK(SP),R1 ;ELSE RETURN THE LOWEST PACKET MOV LOWPR(SP),R0 ;AND THE PREVIOUS PACKETS ADDRESS BR 70$ ;EXIT 20$: BIT #S2.OP1,S.ST2(R4) ;ELEVATOR? BEQ 40$ ;IF EQ NO ; ; ELEVATOR ; TSTB DSKD ;ARE WE GOING OUT? BMI 30$ ;IF MI YES TSTB INEX(SP) ;INWARD PACKET EXIST? BMI 60$ ;IF MI YES - RETURN IT BISB #200,DSKD ;SET GOING OUT 30$: TSTB OUTEX(SP) ;OUTWARD PACKET EXIST? BMI 50$ ;IF MI YES - RETURN IT BICB #200,DSKD ;SET GOING IN BR 60$ ;AND RETURN THE INWARD PACKET ; ; NEAREST CYLINDER ; 40$: TSTB INEX(SP) ;INWARD PACKET EXIST? BPL 50$ ;IF PL NO - RETURN OUTWARD TSTB OUTEX(SP) ;OUTWARD PACKET EXIST? BPL 60$ ;IF PL NO - RETURN INWARD MOV CCYL,R1 ;GET THE CURRENT CYLINDER SUB R1,OUT(SP) ;CALCULATE DISTANCE TO OUTWARD SUB IN(SP),R1 ;CALCULATE DISTANCE TO INWARD CMP R1,OUT(SP) ;INWARD CLOSER? BLO 60$ ;IF LT YES 50$: MOV OUTPK(SP),R1 ;RETURN THE OUTWARD PACKET MOV OUTPR(SP),R0 ;AND THE PREVIOUS PACKETS ADDRESS BR 70$ ;EXIT 60$: MOV INPK(SP),R1 ;RETURN THE INWARD PACKET MOV INPR(SP),R0 ;AND THE PREVIOUS PACKETS ADDRESS 70$: ;REF LABEL RETURN ; ; ; SCAN -- SCAN THE DRIVER QUEUE FOR USABLE PACKETS ; ; THIS ROUTINE IS CALLED TO SCAN A DRIVER QUEUE. ; EACH USABLE ENTRY IN THE QUEUE IS RETURNED. ; ; INPUTS: ; ; R4=SCB ADDRESS FOR THE QUEUE TO BE SCANNED ; ; OUTPUTS: ; ; C=1 IF THERE ARE NO MORE USABLE ENTRIES IN THE QUEUE ; C=0 IF THE NEXT USABLE ENTRY IS BEING RETURNED ; R0=ADDRESS OF THE PREVIOUS PACKET ; R1=ADDRESS OF THE CURRENT PACKET ; R5=UCB ADDRESS FOR THE CURRENT PACKET ; ; NOTE: R0 AND R1 MUST BE PRESERVED BETWEEN CALLS ; TO THIS ROUTINE. ; SCAN: 10$: MOV R1,R0 ;SAVE ADDRESS OF PREVIOUS PACKET MOV (R0),R1 ;GET ADDRESS OF NEXT PACKET BEQ 50$ ;IF EQ NO MORE PACKETS TO SCAN MOV I.UCB(R1),R5 ;GET ADDRESS OF UNIT CONTROL BLOCK TSTB U.STS(R5) ;UNIT BUSY? BMI 10$ ;IF MI YES .IF DF R$$AMD ASSUME US.SIO,200 TSTB U.ST2(R5) ;I/O STALLED TO UNIT ? BPL 15$ ;IF PL, NO CMP $VERTK,I.TCB(R1) ;PACKET FROM VERIFICATION TASK ? BEQ 40$ ;IF EQ, YES. DEQUEUE PACKET BR 10$ ;NO, SEARCH FOR NEXT PACKET .ENDC ; DF R$$AMD 15$: ; MOV U.ATT(R5),R3 ;UNIT ATTACHED? BEQ 40$ ;IF EQ NO CMP #IO.LOV,I.FCN(R1) ;LOAD OVERLAY FUNCTION ? BEQ 17$ ;IF EQ YES CMP #IO.LDO,I.FCN(R1) ;HOW ABOUT LOAD D-SPACE OVERLAY? BNE 20$ ;IF NE NO 17$: TST U.CW1(R5) ;MOUNTABLE DEVICE ? BMI 40$ ;IF MI YES, ALWAYS BREAK THROUGH ATT. 20$: ;REFERENCE LABEL MOV I.TCB(R1),R2 ;GET ADDRESS OF REQUESTOR TASK TCB CMP $RCTPT,R2 ;IS THE I/O FROM RCT? BEQ 40$ ;IF EQ YES, ALWAYS LET IT THROUGH BIT #T3.PRV!T3.CLI,T.ST3(R2) ;TASK PRIVILEGED OR CLI ? BEQ 30$ ;IF EQ NO CMP R2,$LDRPT ;REQUESTING TASK THE LOADER? BEQ 40$ ;IF EQ YES-ALWAYS BREAK THRU ATTACH BIT #DV.TTY,U.CW1(R5) ;DEVICE A TERMINAL? BEQ 30$ ;IF EQ NO CMPB #IO.WLB/256.,I.FCN+1(R1) ;WRITE LOGICAL FUNCTION ? BNE 30$ ;IF NE NO, DON'T BREAKTHROUGH BITB #TF.WBT,I.FCN(R1) ;BREAKTHROUGH WRITE ? BNE 40$ ;IF NE YES, BREAKTHROUGH 30$: CMP R2,R3 ;IS THIS THE APPROPRIATE TASK? BNE 10$ ;IF NE NO 40$: CALL @$TEMP2 ;CALL DRIVER ACCEPTANCE ROUTINE BCS 10$ ;IF CS PACKET NOT ACCEPTED BR 60$ ;RETURN THE PACKET 50$: SEC ;INDICATE NO MORE USABLE PACKETS 60$: RETURN ;EXIT ; ; ACPCHK -- THIS ROUTINE DETERMINES IF A PACKET IS AN ACP FUNCTION ; ; INPUT: ; ; R1=ADDRESS OF THE PACKET ; R5=ADDRESS OF THE UCB ; ; OUTPUT: ; ; C=1 IF THE PACKET IS AN ACP FUNCTION ; C=0 IF NOT ; ACPCHK: TST U.CW1(R5) ;DEVICE MOUNTABLE? BPL 40$ ;IF PL NO BITB #IQ.UMD,I.FCN(R1) ;IS THIS A DIAGNOSTIC FUNCTION? BNE 40$ ;IF NE YES, IT CAN'T BE AN ACP FUNCTION ; ; DETERMINE IF FUNCTION IS ACP FUNCTION ; APPLICABLE TO ALL MOUNTED DEVICES - NATIVE AND FOREIGN ; FILES 11 - MAPPING OF VIRTUAL TO LOGICAL NOW DONE BY ; DRQIO. ONLY VIRTUAL & ACP FUNCTIONS THAT ; NEED CORRECT SEQUENCING ARE ROUTED THRU DRIVER. ; TST U.ACP(R5) ;TEST ADDRESS OF ACP BEQ 40$ ;NO ACP - PASS IT ON TO DRIVER MOVB I.FCN+1(R1),R2 ;GET THE FUNCTION CODE BITB #US.FOR,U.STS(R5) ;MOUNTED FOREIGN (ASSUMED MOUNTED ;WITH AN ACP FROM ABOVE) BNE 10$ ;IF NE YES, CHECK DCB MASKS FOR ACP FUNC. CMP #IO.CLN/400,R2 ;IS IT AN ACP FUNCTION BHI 40$ ;IF HI NO, QUEUE TO DRIVER BR 30$ ;ELSE IS AN ACP FUNCTION 10$: MOV (R5),R3 ;GET DCB ADDRESS CMP R2,#15. ;NORMALIZE FCTN CODE BLOS 20$ ; SUB #16.,R2 ; ADD #10,R3 ;ADJUST PTR TO 2ND MASK SET 20$: ASL R2 ;CONVERT TO WORD INDEX BIT $BTMSK(R2),D.MSK+6(R3) ;IS IT ACP FUNCTION?? BNE 30$ ;IF NE ACP FUNCTION 40$: TST (PC)+ ;CLEAR CARRY FOR DRIVER FUNCTION AND ;SKIP FOLLOWING INSTRUCTION (MOM ;WARNED ME NOT TO CODE LIKE THIS) 30$: SEC ;INDICATE ACP FUNCTION RETURN ; ; DEQUE -- DEQUEUE AN I/O PACKET ; ; THIS ROUTINE DEQUEUES THE CURRENT PACKET. ; ; INPUT: ; ; R0=ADDRESS OF THE PREVIOUS PACKET ; R1=ADDRESS OF THE PACKET TO DEQUEUE ; R4=SCB ADDRESS ; ; OUTPUT: ; ; THE PACKET IS DEQUEUED ; R1 IS UNCHANGED ; DEQUE: MOV (R1),(R0) ;CLOSE UP LIST REMOVING ENTRY BNE 10$ ;IF NE LAST ENTRY WAS NOT REMOVED MOV R0,2(R4) ;SET ADDRESS OF NEW LAST IN LIST 10$: MOV R1,S.PKT(R4) ;SET ADDRESS OF CURRENT I/O PACKET RETURN ;AND EXIT ;+ ; **-$TSTBF-TEST IF I/O BUFFERING CAN BE INITIATED ; ; THIS ROUTINE DETERMINES IF A GIVEN I/O REQUEST IS ELIGIBLE FOR I/O ; BUFFERING, AND IF SO IT STORES THE PCB ADDRESS OF THE REGION INTO ; WHICH THE TRANSFER IS TO OCCUR IN I.PRM+16 OF THE I/O PACKET. ; ; INPUTS: ; ; R3=ADDRESS OF I/O PACKET FOR I/O REQUEST ; ; OUTPUTS: ; ; R3 IS PRESERVED. ; ; C=0 IF I/O BUFFERING CAN BE INITIATED. ; ; C=1 IF I/O BUFFERING CAN NOT BE INITIATED. ;- $TSTBF::SEC ;ASSUME TASK CANNOT BE STOPPED .IF DF R$$IIC BIT #1,I.IOSB+4(R3) ;INTERNAL I/O COMPLETION SPECIFIED? BNE 20$ ;IF NE YES, DON'T BUFFER ANY I/O .ENDC ;R$$IIC MOV I.TCB(R3),R0 ;GET ADDRESS OF REQUESTOR TCB BIT #T2.STP,T.ST2(R0) ;STOP TASK? BNE 20$ ;IF NE NO MOV I.AADA(R3),R0 ;COPY ATTACHMENT DESCRIPTOR ADDRESS MOV A.PCB(R0),R1 ;POINT TO PCB OF TRANSFER BIT #PS.CHK!PS.FXD,P.STAT(R1) ;IS PCB CHECKPOINTABLE? BNE 20$ ;IF NE NO MOV R1,I.PRM+16(R3) ;SET PCB ADDRESS OF TRANSFER CLC ;INDICATE TASK MAY BE STOPPED 20$: RETURN ; ;+ ; **-$INIBF-INITIATE I/O BUFFERING ; ; THIS ROUTINE INITIATES I/O BUFFERING BY DOING THE FOLLOWING: ; ; 1. DECREMENT THE TASK'S I/O COUNT. ; ; 2. INCREMENT THE TASK'S BUFFERED I/O COUNT ; ; 3. INITIATE CHECKPOINTING IF A REQUEST IS PENDING ; ; INPUTS: ; ; R3=ADDRESS OF I/O PACKET FOR I/O REQUEST. ; ; OUTPUTS: ; ; R3 IS PRESERVED. ;- $INIBF::MOV R3,-(SP) ;SAVE PACKET ADDRESS CALL $DECBF ;DEC PCB I/O COUNTS & UNBLOCK TASK MOV I.TCB(R3),R0 ;POINT TO ISSUING TASK'S TCB INCB T.TIO(R0) ;TALLY A BUFFERED I/O REQUEST DECB T.IOC(R0) ;ADJUST OUTSTANDING I/O REQUEST COUNT MOV I.PRM+16(R3),R1 ;GET PCB SUB P.REL(R1),I.PRM(R3) ;CONVERT TO RELATIVE RELOCATION BIAS ADD #T.ST2,R0 ;POINT TO TASK STATUS BITS BIT #T2.AST!T2.WFR,(R0) ;TASK IN AST OR WAITFOR STATE ? BMI 10$ ;IF MI AT AST STATE BEQ 10$ ;IF EQ NOT IN WAITFOR STATE BIS #T2.SEF,(R0) ;STOP THE TASK FOR THE EVENT FLAG 10$: ;REFERENCE LABEL MOV (SP)+,R3 ;RESTORE PACKET ADDRESS IN R3 RETURN ; ;+ ; **-$QUEBF-QUEUE BUFFERED I/O FOR COMPLETION ; ; THIS ROUTINE QUEUES A SPECIAL ENTRY TO A TASK'S AST QUEUE TO COMPLETE ; A BUFFERED I/O REQUEST THE NEXT TIME THE TASK IS SCHEDULED. IT ALSO ; DECREMENTS THE TASK'S BUFFERED I/O COUNT ; ; NOTE: THIS ROUTINE IS EQUIVALENT TO CALLING $IOFIN AND IT DOES NOT ; UNBUSY THE DEVICE. ; ; INPUTS: ; ; R0=FIRST WORD OF I/O STATUS ; R1=SECOND WORD OF I/O STATUS ; R3=ADDRESS OF I/O PACKET ; ; OUTPUTS: ; ; NONE ;- $QUEBF::MOV R0,I.PRM+6(R3) ;STORE OFFSPRING I/O RETURN STATUS MOV R1,I.PRM+10(R3) ; MOV I.TCB(R3),R0 ;PICK UP OFFSPRING TCB ADDRESS MOVB #AK.BUF,A.CBL(R3) ;SET BUFFERED I/O FLAG ;+ ;**-$REQUE-REQUEUE A REGION LOAD AST TO A TASK AST ;**-$REQU1-REQUEUE A REGION LOAD AST TO A TASK AST (ALTERNATE ENTRY) ; ; THESE ROUTINES ARE USED TO QUEUE A TASK KERNEL AST WHICH HAS BEEN ; USED AS A REGION LOAD AST BACK AS A TASK AST. THE BUFFERED I/O ; COUNT OF THE TASK IS DECREMENTED IF ENTRY AT $REQUE. ; ; INPUTS: ; R0=TCB ADDRESS OF ASSOCIATED TASK ; R3=ADDRESS OF PACKET TO BE QUEUED ; ; OUTPUTS: ; NONE. ;- $REQUE:: $REQU1::BIC #TS.CIP!TS.RDN,T.STAT(R0) ;UNBLK TASK MOV R0,R2 ;COPY TCB ADDRESS ADD #T.ASTL,R2 ;POINT TO AST LISTHEAD MOV (R2),(R3) ;LINK PACKET TO FRONT OF LIST BNE 10$ ; MOV R3,2(R2) ; 10$: MOV R3,(R2) ; BIT #T2.SEF,T.ST2(R0) ;TASK IN STOPFOR STATE BNE 12$ ;IF NE YES CALLR $SETCR ;SET CONDITIONAL SCHEDULE REQUEST 12$: CALLR $EXRQU ;UNSTOP TASK AND RETURN ;+ ; **-$IODSA-I/O DONE (FOR DSA DRIVERS) ; **-$IOALT-I/O DONE (ALTERNATE ENTRY) ; **-$IODON-I/O DONE ; ; THIS ROUTINE IS CALLED BY DEVICE DRIVERS AT THE COMPLETION OF AN I/O REQUEST ; TO DO FINAL PROCESSING. THE UNIT AND CONTROLLER ARE SET IDLE AND $IOFIN IS ; ENTERED TO FINISH THE PROCESSING. ; ; INPUTS: ; ; R0=FIRST I/O STATUS WORD. ; R1=SECOND I/O STATUS WORD. ; R2=STARTING AND FINAL ERROR RETRY COUNTS IF ERROR LOGGING ; DEVICE. ; R5=ADDRESS OF THE UNIT CONTROL BLOCK OF THE UNIT BEING COMPLETED. ; (SP)=RETURN ADDRESS TO DRIVER'S CALLER. ; ; NOTE: IF ENTRY IS AT $IOALT, THEN R1 IS CLEAR TO SIGNIFY THAT THE ; SECOND STATUS WORD IS ZERO. ; ; IF ENTRY IS AT $IODSA, UMR DEALLOCATION, DEVICE BUSY STATUS, AND ; ERROR LOGGING FINISH CODE IS SKIPPED ; OUTPUTS: ; ; THE UNIT AND CONTROLLER ARE SET IDLE. ; ; R3=ADDRESS OF THE CURRENT I/O PACKET. ;- .ENABL LSB $IOALT::CLR R1 ;ZERO SECOND I/O STATUS WORD $IODON:: ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER 18. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPH18==. ;SPM CHANGES THE INSTRUCTION AT ;THE LOCATION OF THIS LABEL MOV U.SCB(R5),R4 ;GET ADDRESS OF STATUS CONTROL BLOCK BICB #US.BSY,U.STS(R5) ;CLEAR UNIT BUSY CLRB S.STS(R4) ;CLEAR CONTROLLER BUSY .IF DF E$$LOG&E$$DVC BIT #S2.EIP,S.ST2(R4) ;IS AN ERROR IN PROGRESS? BEQ 15$ ;IF EQ NO MOV R1,-(SP) ;SAVE SECOND I/O STATUS WORD CALL $FNERL ;FINISH ERROR LOGGING PROCESS MOV (SP)+,R1 ;RESTORE I/O STATUS WORD .ENDC ; DF E$$LOG&E$$DVC 15$: ;REFERENCE LABEL .IF DF U$$UMR BIT #FE.EXT,$FMASK ;IS THIS A 22-BIT SYSTEM BEQ 20$ ;IF EQ NO BITB #UC.NPR,U.CTL(R5) ;IS IT AN NPR DEVICE? BEQ 20$ ;IF EQ NO, DOES NOT USE UMR'S MOV S.KRB(R4),R2 ;POINT TO KRB BEQ 20$ ;BLOW OFF ALLOCATING UMRS IF NO KRB BIT #KS.MBC!KS.EXT!KS.DIP,K.STS(R2) ;SHOULD WE NOT DEALLOCATE UMRS? BNE 20$ ;IF NE YES -- DON'T DEALLOCATE ADD K.OFF(R2),R2 ;POINT PAST UMR BLOCK SUB #M.LGTH,R2 ;POINT TO START OF UMR BLOCK CALL $DEUMR ;DEASSIGN ANY UMR'S MOV #$DQUMR,-(SP) ;PUSH ADDRESS TO CHECK FOR UMR WAIT .ENDC ; DF U$$UMR $IOAL2: ;REFERENCE LABEL 20$: MOV S.PKT(R4),R3 ;RETRIEVE ADDRESS OF I/O PACKET .IF DF,P$$MON BR 200$ ; SKIP PERFORMANCE MONITOR NOPS .IFTF ; P$$MON $IODSA:: .IFT ; P$$MON ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER 19. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPH19==. ;SPM CHANGES THE INSTRUCTION AT ;THE LOCATION OF THIS LABEL NOP ;UGLY, BUT WE HAVE TO DO THIS AS ;THERE'S NO OTHER WAY NOP ;TO BE ASSURED OF EXACTLY 2 WORDS ;TO REPLACE. 200$: ;REFERENCE LABEL TO BYPASS THE NOPS ;EXCEPT FOR $IODSA .ENDC .IF DF E$$LOG&E$$DVC BIT #S2.LOG,S.ST2(R4) ;ERROR LOGGING (MASS STORE) ? BEQ 23$ ;IF EQ NO .IF DF X$$ACC&A$$CNT&XA$IO BIT #1,I.IOSB+4(R3) ; WAS THIS AN INTERNAL IOC? BNE 23$ ; YUP, WE'LL SEE THE REAL IOC LATER .ENDC ;DF X$ACC&A$$CNT&XA$IO TALLY$ B.MIOC,XA$$IO,CPU ;COUNT A MASS STORE I/O COMPLETION 23$: .ENDC ; DF E$$LOG&E$$DVC .IF DF Q$$OPT TST (R4) ;ANY OTHER I/O REQUESTS TO INITIATE? BEQ 25$ ;IF EQ GO TO $IOFIN MOV R3,R4 ;COPY I/O PACKET POINTER ADD #I.PRM+14,R4 ;POINT TO LAST WORD FOR FORK BLOCK MOV R0,(R4) ;STORE I/O STATUS BLOCK CONTENTS MOV R1,-(R4) ; .IF DF M$$PRO MOV $CPBIT,-6(R4) ;SET UP OUR URM FOR FORK0 .ENDC CALL $FORK0 ;FORK HERE TO ALLOW NEXT I/O INITIATION MOV R4,R0 ;RESTORE I/O STATUS BLOCK CONTENTS MOV R5,R1 ; SUB #I.PRM+10,R3 ;POINT TO BEGINNING OF I/O PACKET .ENDC 25$: MOV I.UCB(R3),R5 ;GET UCB ADDRESS OF I/O REQUEST .IF DF S$$HDW CALL $SHFND ;IS THIS UNIT SHADOW RECORDED? BCC 251$ ;IF CC YES JMP IOFIN2 ;GO TO $IOFIN 251$: TSTB ML.DNC(R4) ;IS THIS FIRST PACKET THRU SYSTEM? BNE 40$ ;IF NE NO -- MUST DECIDE WHAT TO TELL USER ; ; THIS I/O PACKET IS THE FIRST ONE TO GO THRU THE SYSTEM. IF ; IT IS A WRITE PACKET, THEN WE MUST WAIT TO SEE THE OUTCOME OF ; THE SECOND PACKET. ; CMPB #IO.WLB/400,I.FCN+1(R3) ;IS IT A WRITE? BNE 26$ ;IF NE NO -- CHECK FOR OTHER FUNCTIONS CALLR $SHSAV ;IF EQ YES -- SAVE STS AND WAIT FOR OTHER PKT 26$: CMP #IO.SCF,I.FCN(R3) ;IS THIS A SHADOW COPY FUNCTION? BEQ 28$ ;IF EQ YES CMPB #IO.RLB/400,I.FCN+1(R3) ;IS THIS A READ FUNCTION? BNE 271$ ;IF NE NO -- DON'T KNOW WHAT IT IS ;BETTER EXIT NOW ; ; THIS FUNCTION IS AN IO.RLB FUNCTION (READ) AND NO SPECIAL COPY ; SUBFUNCTION WAS SPECIFIED. WE NOW MUST CHECK TO SEE IF THE ; READ COMPLETED SUCCESSFULLY. ; CMP R0,#IS.SUC ;WAS IT SUCCESSFUL? BEQ 271$ ;IF EQ YES -- EXIT ; ; THE FUNCTION IS A READ, AND THE FIRST I/O PACKET FAILED. NOW ; WE MUST DETERMINE WHETHER WE NEED TO CHECK THE FENCE (WHICH ; MEANS THAT CATCHUP IS ACTIVE) PRIOR TO TRYING THE OTHER PACKET. ; ; In addition, if a file structure catchup is active (Shadow update) ; we will not allow the packet to be queued to the secondary on a read. ; ; The ultimate goal during the "UPDATE" function is to insure that all ; writes are shadowed across the volume, and once the file structure is ; stable, all I/O operations will be shadowed/shared. ; ; If load sharing is enabled, and the first packet queued was the ; secondary packet, we can't validate the LBN, but we must go and ; queue the primary packet, to try and get the best results ; CMP R3,ML.PRI(R4) ; Was this the primary packet through? BNE 30$ ; Nope, was secondary, go requeue the primary MOV R5,-(SP) ;SAVE UCB ADDRESS MOV U.UMB(R5),R5 ;GET UMB ADDRESS BITB #MS.CHP,M.STS(R5) ;IS AN UPDATE IN PROGRESS SEC ;ASSUME IT IS BNE 261$ ;UPDATE IS IN PROGRESS, DON'T READ YET CALL $CKLBN ;IS LBN RANGE BELOW FENCE? 261$: MOV (SP)+,R5 ;RESTORE UCB ADDRESS BCC 30$ ;IF CC YES 27$: CALL $SHSAV ;SAVE STATUS MOV R3,-(SP) ;PREPARE TO LOG ERROR MOV R3,-(SP) ;PREPARE SOME MORE BR 45$ ;GO LOG SHADOW RECORDING ERROR 271$: JMP IOFIN1 ;EXIT 28$: .IF DF S$$HLS ; SHADOW LOAD SHARING TSTB R0 ; WAS THE I/O SUCCESS? BGT 29$ ; IF GT, YES, CONTINUE CMP R3,ML.PRI(R4) ; IS THIS THE PRIMARY I/O PACKET? BNE 27$ ; IF NE, WE NEED TO REPORT THE ERROR MOV R0,-(SP) ; SAVE R0 MOV U.UMB(R5),R0 ; GET THE UMB ADDRESS BITB #MS.CHP,M.STS(R0) ; IS THIS AN UPDATE/MERGE OPERATION? BEQ 288$ ; IF EQ, NOPE, MUST BE START OPERATION CMP I.PRM+4(R2),#512. ; IS THIS A RECOVERY OPERATION? BEQ 283$ ; IF EQ, YES, PROCEED ... 282$: MOV (SP)+,R0 ; RESTORE THE STATUS BR 27$ ; AND RETURN THE ERROR ;+ ; A FORCED ERROR MARK IS THE ONLY *KNOWN* ERROR WHICH WOULD BE ; SUITABLE FOR ATTEMPTING TO RECOVER DURING A MERGE OPERATION. ;- 283$: CMPB (SP),#IE.FER ; IS THIS A FORCED ERROR MARK? BNE 282$ ; NOPE, DON'T CLOBBER THE DESTINATION DRIVE ;+ ; AT THIS STAGE, WE HAVE AN IE.FER ON THE SOURCE DRIVE, AND WHAT ; WOULD HOPE TO BE A VALID BLOCK ON THE SECONDARY DRIVE. WE WILL NOW ; TRY TO MIGRATE THE BLOCK BACK FROM THE SECONDARY PACK ... ; ; INPUT: ; R0 - SCRATCH ; R2 - OTHER (SECONDARY) IOP ; R3 - THIS (PRIMARY) IOP ; R4 - ML NODE ; R5 - PRIMARY UCB ADDRESS ;- CLRB ML.DNC(R4) ; RESET THE DONE COUNT MOV #I.LGTH/2,R0 ; SET UP THE LENGTH TO COPY MOV R3,R1 ; COPY PRIMARY PACKET TO R1 284$: MOV (R2)+,(R1)+ ; COPY THE PACKET BACK TO THE PRIMARY SOB R0,284$ ; AND COPY THE WHOLE THING SUB #I.LGTH,R2 ; RESET THE SECONDARY PACKET ADDRESS MOV R5,I.UCB(R3) ; RESET THE UCB ADDRESS IN PRIMARY TST (SP)+ ; REMOVE THE STACKED R0 BR 32$ ; AND QUEUE THE IO.SCF TO THE SEC 288$: MOV (SP)+,R0 ; RESTORE R0 (PRIMARY I/O STATUS) 29$: .ENDC ;DF,S$$HLS ; SHADOW LOAD SHARING MOV #IO.WLB,I.FCN(R2) ;SET WRITE LOGICAL BLOCK FUNCTION MOVB #251.,I.PRI(R2) ;SET PRIORITY TO THE HIGHEST POSSIBLE ; ; I/O PACKET IS A FAILED READ OR A READ/WRITE COMBINED. WE NOW WILL ; ATTEMPT TO QUEUE THE PACKET TO THE ALTERNATE DRIVE AND SEE IF ; WE CAN'T GET SOME BETTER RESULTS TO TELL THE USER. ; 30$: CALL $SHSAV ;SAVE STATUS IN I/O PACKET 32$: MOV I.UCB(R2),R5 ;GET UCB ADDRESS MOV R2,R1 ;COPY I/O PACKET ADDRESS CALLR $DRQRQ ;TRY OTHER I/O PACKET TO OTHER DRIVE ; ; AT THIS POINT, WE HAVE DONE TWO PACKETS. ; WE MUST CONSOLIDATE THE RESULTS TO PASS TO THE USER. ; 40$: CALL $SHSAV ;SAVE STATUS TSTB I.R0(R2) ;ERROR FROM FIRST PACKET? BMI 42$ ;IF MI YES TSTB R0 ;ERROR FROM SECOND? BMI 42$ ;IF MI YES JMP IOFIN1 ;SUCCESS FROM BOTH PACKETS ; ; WE HAVE DETERMINED THAT AT LEAST ONE OF THE STATUS ; RETURN CODES SHOWED AN ERROR CONDITION. ; 42$: MOV ML.PRI(R4),R3 ;GET PRIMARY I/O PACKET ADDRESS MOV R4,R2 ;COPY ML NODE ADDRESS ADD #ML.PKT,R2 ;R2 = SECONDARY PACKET ADDRESS MOV I.R0(R3),ML.PR0(R4) ;SAVE STATUS FROM PRIMARY PACKET MOV I.R1(R3),ML.PR1(R4) ;SAVE STATUS FROM PRIMARY PACKET MOV R3,-(SP) ;SAVE PRIMARY PACKET ON STACK MOV R3,-(SP) ;SAVE PRIMARY PACKET ON STACK CMP #IO.SCF,I.FCN(R3) ;IS THIS A SHADOW COPY FUNCTION? BNE 43$ ;IF NE NO TSTB I.R0(R3) ;IS THE PRIMARY STATUS OK? BMI 45$ ;IF MI NO BR 44$ ;RETURN SECONDARY STATUS 43$: TSTB I.R0(R3) ;HOW DOES PRIMARY STATUS LOOK? BPL 45$ ;IF PL OK 44$: MOV R2,(SP) ;RETURN STATUS FROM SECONDARY PACKET ; ; WE HAVE DECIDED WHICH STATUS TO RETURN TO THE USER. ; 45$: MOV R4,R1 ;COPY ML NODE ADDRESS MOV U.UMB(R5),R0 ; GET THE UMB ADDRESS BITB #MF.DSE,M.FLG(R0) ; HAS SHE... BEEN DISABLED? BNE 46$ ; YUP, DROP THE ERROR PACKET MOV $SHERR,R0 ;GET TCB ADDRESS OF THE ERROR TASK BEQ 46$ ;IF EQ NO ERROR TASK CMP $SHPCT,$SHLIM ;DO WE ALREADY HAVE ENOUGH PACKETS ? BLT 451$ ;IF LT NO, GO AHEAD WITH THIS ONE TST $SHLOS ;HAVE WE LOST TOO MANY TO KEEP TRACK OF ? BMI 46$ ;IF MI YES, DON'T COUNT THIS ONE INC $SHLOS ;COUNT ONE MORE LOST BR 46$ ;AND THROW IT AWAY 451$: INC $SHPCT ;COUNT ONE MORE IN QUEUE CLR ML.FID(R4) ;INITIALIZE FILE ID FOR ERROR TASK CLR ML.FSEQ(R4) ;INITIALIZE FILE SEQUENCE NUMBER CALL GETWIN ;GET WINDOW ADDRESS, IS THERE ONE? BEQ 454$ ;IF EQ THERE IS NO WINDOW BLOCK MOV W.FCB(R2),R2 ;GET FCB ADDRESS BEQ 454$ ;IF EQ, NO FILE CONTROL BLOCK MOV KISAR5,-(SP) ;SAVE PAR 5 MOV R3,-(SP) ;SAVE R3 CMP R2,#120000 ;IS THE FCB WITHIN THE ACP? BLO 452$ ;IF LO NO MOV I.UCB(R3),R3 ;GET UCB ADDRESS MOV U.ACP(R3),R3 ;GET ACP ADDRESS MOV T.OFF(R3),KISAR5 ;PICK UP OFFSET INTO TASK REGION OF ACP .IF DF U$$DAS ;DC437 MOV T.ST4(R3),-(SP) ; SAVE FOR I/D SPACE ACP ;DC437 .IFTF ;DF,U$$DAS ;DC437 MOV T.PCB(R3),R3 ;GET PCB ADDRESS FOR THE ACP BIT #PS.CKP!PS.CKR!PS.OUT,P.STAT(R3) ;IS ACP CHECKPOINTED? BNE 453$ ;IF NE YES .IFT ;DF,U$$DAS ;DC437 BIT #T4.DSP,(SP) ; IS THIS AN I/D SPACE TASK ;DC437 BEQ 4515$ ; IF EQ, NOPE, CONTINUE ;DC437 MOV P.REL(R3),KISAR5 ;MAP THE ACP TASK HEADER ;DC437 MOV @#120000+H.WND,(SP) ; GET THE WINDOW POINTER ;DC437 ADD #<<2-20000>+W.BLGH+W.BOFF>,(SP) ; POINT TO THE WINDOW OFFSET ;DC437 MOV @(SP),KISAR5 ; GET THE OFFSET WORD FOR WINDOW #1 ;DC437 4515$: ; REFERENCE LABEL ;DC437 .IFTF ;DF,U$$DAS ;DC437 ADD P.REL(R3),KISAR5 ;MAP THE ACP TASK REGION THROUGH APR 5 CMP R2,#140000 ;IS THE FCB MAPPED BY APR 6? BLO 452$ ;IF LO NO SUB #20000,R2 ;CONVERT FCB ADDRESS TO APR 5 BIAS ADD #200,KISAR5 ;ADJUST MAPPING TO NEXT 4K OF FCP 452$: MOV F.FNUM(R2),ML.FID(R4) ;MOVE FILE ID TO ML NODE MOV F.FSEQ(R2),ML.FSEQ(R4) ;MOVE FILE SEQUENCE NUMBER 453$: .IFT ;DF,U$$DAS ;DC437 TST (SP)+ ;CLEAN THE STACK ;DC437 .ENDC ;DF,U$$DAS ;DC437 MOV (SP)+,R3 ;RESTORE R3 ;DC437 MOV (SP)+,KISAR5 ;RESTORE KERNEL PAR 5 ;**-1 454$: CALL $DLNK ;REMOVE THE ML NODE FROM THE LIST MOV ML.TCB(R4),R3 ;GET ADDRESS OF TCB MOV T.NAM(R3),ML.TCB(R4) ;PUT TASK NAME IN PACKET MOV T.NAM+2(R3),ML.TCB+2(R4) ; CALL $EXRQF ;QUEUE ML NODE TO ERROR TASK 46$: MOV (SP)+,R3 ;GET I/O PACKET ADDRESS FROM STACK MOV I.R0(R3),R0 ;GET PROPER STATUSES MOV I.R1(R3),R1 ;GET PROPER STATUSES MOV (SP)+,R3 ;GET REAL I/O PACKET ADDRESS .ENDC ; DF S$$HDW .IF DF P$$MON BR P1 ;BYPASS IOFIN HOOKPOINT .ENDC .DSABL LSB ;+ ; **-$IOFIN-I/O FINISH ; ; THIS ROUTINE IS CALLED TO FINISH I/O PROCESSING IN CASES WHERE THE UNIT AND ; CONTROLLER ARE NOT TO BE DECLARED IDLE. IF THE TASK WHICH ISSUED THE ; I/O HAS HAD A RECENT MAPPING CHANGE WHICH MAY HAVE UNMAPPED ITS I/O ; STATUS BLOCK, THE I/O PACKET IS QUEUED TO THE FRONT OF ITS AST QUEUE ; TO BE COMPLETED LATER IN $FINBF BY CALLING $IOFIN AGAIN. ; ; INPUTS: ; ; R0=FIRST I/O STATUS WORD. ; R1=SECOND I/O STATUS WORD. ; R3=ADDRESS OF THE I/O REQUEST PACKET. ; ; OUTPUTS: ; ; THE FOLLOWING ACTIONS ARE PERFORMED ; ; 1-THE FINAL I/O STATUS VALUES ARE STORED IN THE I/O STATUS BLOCK IF ; ONE WAS SPECIFIED. ; ; 2-ALL ASSOCIATED I/O COUNTS ARE DECREMENTED AND TS.RDN IS ; CLEARED IN CASE THE TASK WAS BLOCKED FOR I/O RUNDOWN. ; T3.MPC IS CLEARED IF THE TASK I/O COUNT GOES TO ZERO TO ; INDICATE THAT THE I/O COUNT WENT TO ZERO AFTER A MAPPING ; CHANGE. ; ; 3-IF 'TS.CKR' IS SET, THEN IT IS CLEARED AND CHECKPOINTING OF ; THE TASK IS INITIATED. ; ; 4-IF AN AST SERVICE ROUTINE WAS SPECIFIED, THEN AN AST IS QUEUED ; FOR THE TASK. ELSE THE I/O PACKET IS DEALLOCATED. ; ; 5-A SIGNIFICANT EVENT OR EQUIVALENT IS DECLARED. ; ; NOTE: R4 IS DESTROYED BY THIS ROUTINE. ;- $IOFIN:: ;REFERENCE LABEL .IF DF P$$MON ;+ ; ** W A R N I N G ** ; ; SPM HOOKPOINT NUMBER 35. ; ; DO NOT CHANGE THE INSTRUCTION FOLLOWING ; LABEL WITHOUT CHECKING SPM ;- $SPH35==. ;SPM CHANGES THE INSTRUCTION AT ;THE LOCATION OF THIS LABEL NOP ;UGLY, BUT IT'S THE ONLY WAY WE ;CAN ASSURE TWO INSTRUCTIONS NOP ;TO PICK UP AND REPLACE WITH THE ;SPM HOOKS P1: .ENDC .ENABL LSB .IF DF R$$AMD ;AUTOMOUNT/DISMOUNT ; NOTE THAT THIS CODE WILL NOT WORK IF EITHER ERROR LOGGING OR ; SHADOW RECORDING IS TURNED ON TSTB R0 ;ERROR IN PROCESSING I/O REQUEST ? BPL 100$ ;IF PL, NO MOV I.UCB(R3),R4 ;YES, GET UCB ADDRESS ASSUME US.SIO,200 TSTB U.ST2(R4) ;I/O STALLED TO UNIT ? BPL 100$ ;IF PL, NO - PASS ERRORS TO TASK CMP $VERTK,I.TCB(R3) ;I/O REQUEST FROM VERIFICATION TASK ? BEQ 100$ ;IF EQ, YES - PASS ERRORS TO TASK MOV U.SCB(R4),R0 ;GET SCB LISTHEAD FOR I/O PACKETS MOV R3,R1 ;GET CURRENT I/O PACKET ADD #U.SPRM,R4 ;POINT TO PARAMETER SAVE AREA IN UCB ADD #I.PRM+6,R3 ;POINT TO READ/WRITE CELLS IN I/O PACKET MOV (R4)+,(R3)+ ;RESTORE MOV (R4)+,(R3)+ ; I/O MOV (R4)+,(R3)+ ; PACKET MOV (R4),(R3) ; CALL $QINSB ;RE-INSERT PACKET AT FRONT OF QUEUE RETURN ; 100$: ;REFERENCE LABEL .ENDC ; DF R$$AMD .IF DF S$$HDW MOV R5,-(SP) ;SAVE R5 MOV I.UCB(R3),R5 ;SET UCB ADDRESS FOR SHADOW RECORDING CALL $SHFND ;SEE IF WE HAVE PACKET PROBLEMS MOV (SP)+,R5 ;RESTORE R5 BCS IOFIN2 ;IF CS NO SHADOW RECORDING ; ; THIS IS THE POINT WHERE WE WILL DEALLOCATE AN ML NODE AND RETURN ; THE STATUS IN THE REGISTERS TO THE USER. ALL PROCESSING CONCERNED ; WITH STATUS RETURNS MUST HAVE BEEN RESOLVED AT THIS POINT. ; IOFIN1: CALL $DLNK ;REMOVE ML NODE FROM LIST ON UMB MOV ML.PRI(R4),R3 ;GET PRIMARY I/O PACKET ADDRESS MOV R3,-(SP) ;SAVE I/O PACKET ADDRESS MOV R1,-(SP) ;SAVE STATUS MOV R0,-(SP) ;SAVE STATUS MOVB ML.LEN(R4),R1 ;GET LENGTH OF ML NODE MOV R4,R0 ;COPY ML NODE ADDRESS CALL $DEACB ;RELEASE STORE FOR ML NODE MOV (SP)+,R0 ;RESTORE STATUS MOV (SP)+,R1 ;RESTORE STATUS MOV (SP)+,R3 ;RESTORE I/O PACKET ADDRESS IOFIN2: ;REFERENCE LABEL .ENDC TALLY$ B.AIOC,XA$$IO,CPU ;COUNT AN I/O COMPLETION MOV R0,I.PRM+6(R3) ;STORE FIRST WORD OF I/O STATUS MOV R1,I.PRM+10(R3) ;STORE SECOND WORD OF I/O STATUS TSTB I.EFN(R3) ;VIRTUAL I/O FUNCTION? BPL 205$ ;IF PL NO BICB #200,I.EFN(R3) ;CLEAR VIRTUAL FLAG BIT #1,I.LN2(R3) ;HEADER LOCKED DOWN FOR ACP? BNE 1$ ;IF NE NO MOV I.TCB(R3),R0 ;THE I/O PACKET IS CONNECTED TO THE TCB MOV T.ATT(R0),R0 ;THE TCB IS CONNECTED TO THE ADB SUB #A.TCBL,R0 ;FIND THE FOOT CALL $DECIO ;UNLOCK THE HEADER 1$: ;REFERENCE LABEL MOV #205$,-(SP) ;FAKE RETURN ADDRESS $DCWIO::MOV $WCFLG,R0 ;GET UCB FLAG FOR TEST BEQ 11$ ;IF EQ W.IOC DISABLED MOV I.UCB(R3),R2 ;GET DEVICE UCB ADDRESS BIT R0,U.CW1(R2) ;FILES-11 DEVICE ? BEQ 2$ ;IF EQ, NO CALL GETWIN ;GET WINDOW ADDRESS, IS THERE ONE ? BEQ 2$ ;IF EQ, NO DECB W.IOC(R2) ;DECREMENT WINDOW I/O COUNT 11$: ; .IF DF R$$LKL MOV I.PRM+16(R3),R0 ;PICK UP LOCK BLOCK ADDRESS BEQ 2$ ;IF EQ THERE IS NONE CMP R0,#140000 ;IS IT A RELOCATED USER ADDRESS ? BHIS 2$ ;IF HIS, YES DEC (R0) ;FREE LOCK FOR UNLOCKING .ENDC ; DF R$$LKL 2$: RETURN 205$: ;REFERENCE LABEL MOV I.IOSB+4(R3),R2 ;GET ADDRESS OF I/O STATUS BLOCK BEQ 10$ ;IF EQ NO I/O STATUS BLOCK SPECIFIED .IF DF R$$IIC BIT #1,R2 ;INTERNAL I/O COMPLETION REQUESTED? BEQ 21$ ;IF LO BIT NOT SET, NO DEC R2 ;CLEAR LO BIT MOV KISAR5,-(SP) ;SAVE CURRENT KISAR5 MAPPING MOV KISAR6,-(SP) ;SAVE CURRENT KISAR6 MAPPING MOV I.IOSB+2(R3),KISAR5 ;MAP I/O COMPLETION ROUTINE MOV KISAR5,KISAR6 ;ROUTINE MAY BE MAPPED THROUGH KISAR6 .IF DF K$$DAS MOV KINAR5,-(SP) ;SAVE I-SPACE 5 MOV KINAR6,-(SP) ;SAVE I-SPACE 6 MOV KISAR5, KINAR5 ;MAP I-SPACE 5 MOV KISAR6, KINAR6 ;MAP I-SPACE 6 .IFTF ; K$$DAS CALL (R2) ;CALL INTERNAL I/O COMPLETION ROUTINE .IFT ; K$$DAS MOV (SP)+,KINAR6 ;RESTORE SAVED MAPPING CONTEXT MOV (SP)+,KINAR5 ;... .ENDC ; K$$DAS MOV (SP)+,KISAR6 ;RESTORE SAVED MAPPING CONTEXT MOV (SP)+,KISAR5 ; RETURN ;DONE 21$: ;REF LABEL .ENDC ;R$$IIC MOV I.TCB(R3),R0 ;POINT TO ISSUING TASK TCB BIT #TS.BLC,T.STAT(R0) ;TASK BLOCKED (CHECKPOINTED) ? BNE 3$ ;IF NE YES, DEFER I/O STATUS UPDATE BIT #T3.MPC,T.ST3(R0) ;RECENT MAPPING CHANGE? BEQ 5$ ;IF EQ NO 3$: CALL $SETCR ;RESCHEDULE TASK TO LOOK AT AST QUEUE MOV R3,R1 ;COPY I/O PACKET POINTER MOVB #AK.DIO,A.CBL(R1) ;INDICATE DELAYED I/O COMPLETION ADD #T.ASTL,R0 ;POINT TO TASK AST QUEUE LISTHEAD CALL $QINSB ;INSERT BLOCK AT BEGINNING OF QUEUE BR $DECAL ;DEC I/O COUNTS, UNBLK TASK & RETURN 5$: MOV KISAR6,-(SP) ;SAVE CURRENT MAPPING MOV I.IOSB+2(R3),KISAR6 ;MAP TO I/O STATUS BLOCK MOV I.PRM+6(R3),(R2)+ ;SET FINAL I/O STATUS VALUES MOV I.PRM+10(R3),(R2) ; MOV (SP)+,KISAR6 ;RESTORE CURRENT MAPPING 10$: CALL $DECAL ;DEC I/O COUNTS & UNBLOCK TASK MOV I.TCB(R3),R1 ;GET ADDRESS OF TASK CONTROL BLOCK DECB T.IOC(R1) ;DECREMENT I/O REQUEST COUNT BNE 15$ ;IF NE TASK STILL HAS OUTSTANDING I/O BIC #T3.MPC,T.ST3(R1) ;CLEAR MAPPING CHANGE BIT 15$: ;REF LABEL MOV I.TCB(R3),R1 ;PICK UP ISSUING TASK'S TCB ADDRESS MOV R5,-(SP) ;SAVE UCB ADDRESS MOV I.TCB(R3),R5 ;SET TCB ADDRESS MOVB I.EFN(R3),R0 ;GET EVENT FLAG NUMBER CALL $SETFG ;SET EFN AND UNLOCK IF GROUP GLOBAL MOV R3,R0 ;COPY I/O PACKET ADDRESS TST (R3)+ ;POINT TO SECOND WORD MOV #I.LGTH,(R3)+ ;INSERT LENGTH OF BLOCK IN BYTES MOV #8.*2,(R3)+ ;SET NUMBER OF BYTES TO ALLOCATE ON USER STACK MOV I.AST(R0),(R3)+ ;INSERT AST ADDRESS BEQ 70$ ;IF EQ NONE SPECIFIED MOV #1,(R3)+ ;INSERT NUMBER OF AST PARAMETERS MOV I.IOSB(R0),(R3) ;INSERT VIRTUAL ADDRESS OF I/O STATUS BLOCK MOV R0,R1 ;COPY ADDRESS OF I/O PACKET MOV R5,R0 ;CALCULATE ADDRESS OF AST LISTHEAD ADD #T.ASTL,R0 ; CALL $QINSF ;INSERT AST IN QUEUE MOV R5,R0 ;COPY TCB ADDRESS CALL $SETCR ;SET TASK SCHEDULE REQUEST BR 80$ ; 70$: CALL $DEPKT ;DEALLOCATE I/O PACKET 80$: MOV (SP)+,R5 ;RESTORE UCB ADDRESS RETURN ; .DSABL LSB ;+ ; *-GETWIN-GET FILE WINDOW ADDRESS ; ; INPUT: ; R3=I/O PACKET ADDRESS ; ; OUTPUT: ; R2=WINDOW ADDRESS ; Z-BIT SET IF NO WINDOW ;- GETWIN: MOV I.LN2(R3),R2 ;GET IMAGE OF LUT2 OR ADDRESS OF LUT2 BIT #1,R2 ;ADDRESS? BNE 10$ ;IF NE NO .IF DF X$$HDR MOV KISAR6,-(SP) ;SAVE CURRENT MAPPING MOV I.TCB(R3),R2 ;GET TCB ADDRESS MOV T.PCB(R2),R2 ;GET PCB ADDRESS OF TASK REGION MOV P.REL(R2),KISAR6 ;ASSUME WE NEED TO MAP HEADER .IFTF MOV @I.LN2(R3),R2 ;GET CONTENTS OF LUT2 .IFT MOV (SP)+,KISAR6 ;RESTORE MAPPING .ENDC 10$: BIC #1,R2 ;CLEAR POSSIBLE INTERLOCK, WINDOW? RETURN ; ;+ ; **-$DECAL-DECREMENT ALL I/O COUNTS AND UNBLOCK TASK ; ; THIS ROUTINE IS CALLED ON I/O COMPLETION TO DECREMENT ALL I/O ; COUNTS IN ATTACHMENT DESCRIPTORS AND TO UNBLOCK THE TASK FOR ; CHECKPOINT IN PROGRESS OR I/O RUNDOWN. ; ; INPUTS: ; ; R3=ADDRESS OF I/O PACKET. ; ; OUTPUTS: ; ; NONE. ;- $DECAL::MOV I.AADA(R3),R0 ;DEC I/O COUNT IN 1ST ATT DESC? BEQ 10$ ;IF EQ NO CLR I.AADA(R3) ;CLEAR ATT DESCR PTR CALL $DECIO ;DECREMENT THE COUNT 10$: MOV I.AADA+2(R3),R0 ;DEC I/O COUNT IN 2ND ATT DESCR? BEQ 20$ ;IF EQ NO CLR I.AADA+2(R3) ;CLEAR ATT DESCR PTR CALL $DECIO ;DECREMENT THE COUNT 20$: MOV I.TCB(R3),R0 ;POINT TO ISSUING TASK TCB BIC #TS.CIP!TS.RDN,T.STAT(R0) ;UNBLOCK TASK RETURN ; ;+ ; **-$DECBF-DECREMENT ALL PARTITION I/O COUNTS AND UNBLOCK TASK ; ; THIS ROUTINE IS CALLED ON BUFFERINT I/O TO DECREMENT ALL I/O ; COUNTS IN PCBS AND TO UNBLOCK THE TASK FOR CHECKPOINT IN ; PROGRESS OR I/O RUNDOWN. ; ; INPUTS: ; ; R3=ADDRESS OF I/O PACKET. ; ; OUTPUTS: ; ; NONE. ;- $DECBF::MOV R3,-(SP) ;SAVE I/O PACKET ADDRESS MOV I.AADA(R3),R0 ;DEC I/O COUNT IN 1ST ATT DESCR? BEQ 10$ ;IF EQ NO BIS #1,I.AADA(R3) ;INDICATE BUFFERED I/O CALL $DECIP ;DECREMENT THE COUNT MOV (SP),R3 ;RESTORE PACKET ADDRESS 10$: MOV I.AADA+2(R3),R0 ;DEC I/O COUNT IN 2ND ATT DESCR? BEQ 20$ ;IF EQ NO BIS #1,I.AADA+2(R3) ;INDICATE BUFFERED I/O CALL $DECIP ;DECREMENT THE COUNT 20$: MOV (SP)+,R3 ;RESTORE PACKET ADDRESS MOV I.TCB(R3),R0 ;POINT TO ISSUING TASK TCB BIC #TS.CIP!TS.RDN,T.STAT(R0) ;UNBLOCK TASK RETURN ; ;+ ; **-$IOKIL-I/O KILL ; ; THIS ROUTINE IS CALLED TO FLUSH ALL I/O REQUESTS FOR THE CURRENT TASK FROM ; A DEVICE QUEUE AND TO CANCEL THE CURRENT I/O OPERATION IN PROGRESS IF IT ; IS ALSO FOR THE CURRENT TASK. ; ; INPUTS: ; ; R5=ADDRESS OF THE UCB OF THE DEVICE TO FLUSH REQUESTS FOR. ; ; OUTPUTS: ; ; IF THE SPECIFIED DEVICE IS NOT FILE STRUCTURED, THEN THE I/O RE- ; REQUEST QUEUE IS FLUSHED AND THE CURRENT I/O OPERATION IN PROGRESS ; IS CANCELLED. ; ; NOTE: R4 IS DESTROYED BY THIS ROUTINE. ;- $IOKIL:: .IF DF M$$PRO CLR $TEMP0 ;INDICATE THIS IS NOT DRQIO CALLING .ENDC ; DF M$$PRO $IOKL1::CLR $TEMP2 ;SET INDICATOR TO FLUSH ASTS $IOKL2::MOV U.SCB(R5),R4 ;GET ADDRESS OF SCB MOV $TKTCB,R1 ;GET TCB ADDRESS OF CURRENT TASK TST U.CW1(R5) ;DEVICE-UNIT MOUNTABLE? BPL 10$ ;IF PL NO BITB #US.MNT,U.STS(R5) ;DEVICE-UNIT MOUNTED? BNE 10$ ;IF EQ NO - FLUSH QUEUE TST U.ACP(R5) ;DEVICE HAVE ACP (ALSO CATCHES NOT FOREIGN) BNE 40$ ;IF NE ES, CAN'T FLUSH QUEUE 10$: .IF DF C$$RTK ;REMOTE TASK SUPPORT BIT #F5.RTK,$FMSK5 ;IS REMOTE TASK SUPPORT TURNED ON? BEQ 15$ ;IF EQ NO CMP (R5),$XXLOW ;IS THE DCB ADDRESS IN THE GENERIC RANGE? BLO 15$ ;IF LO NO CMP (R5),$XXHGH ;IS IT? BLOS 40$ ;IF LO OR SAME, YES DON'T FLUSH QUEUE YET .ENDC ;C$$RTK 15$: MOV R4,R3 ;COPY ADDRESS OF I/O QUEUE LISTHEAD 20$: MOV R3,R2 ;SAVE ADDRESS OF CURRENT ENTRY MOV (R2),R3 ;GET ADDRESS OF NEXT ENTRY BEQ 40$ ;IF EQ END OF LIST CMP R1,I.TCB(R3) ;REQUEST FOR CURRENT TASK? BNE 20$ ;IF NE NO CMP R5,I.UCB(R3) ;REQUEST FOR SPECIFIED UCB? BNE 20$ ;IF NE NO MOV (R3),(R2) ;CLOSE UP LIST BNE 30$ ;IF NE NO NEW LAST MOV R2,2(R4) ;SET ADDRESS OF NEW LAST 30$: MOV #IE.ABO&377,R0 ;SET FINAL STATUS TO ABORT TSTB $TEMP2 ;SUBFUNCTION BIT SET FOR IO.KIL ? BMI 35$ ;IF MI YES CLR I.AST(R3) ;MAKE SURE THERE IS NO AST DECLARED 35$: CLR R1 ;CLEAR R1 BEFORE CALLING $IOFIN CALL $IOFIN ;FINISH I/O REQUEST BR $IOKL2 ;GO AGAIN 40$: TSTB U.STS(R5) ;UNIT BUSY? BMI 45$ ;IF MI YES -- ALWAYS CALL DRIVER .IF DF M$$PRO MOV U.SCB(R5),R4 ;GET SCB ADDRESS MOV S.KRB(R4),R4 ;GET KRB ADDRESS (IF ANY) BEQ 44$ ;IF EQ NO KRB -- CALL DRIVER? BIT K.URM(R4),$URMST ;IS THE KRB'S URM ONLINE? BEQ 50$ ;IF EQ NO -- DON'T CALL DRIVER .ENDC 44$: BITB #UC.KIL,U.CTL(R5) ;CALL DRIVER REGARDLESS OF ACTIVITY BEQ 50$ ;IF EQ NO -- EXIT BITB #US.OFL,U.ST2(R5) ;DEVICE ONLINE ? BNE 50$ ;IF NE NO -- EXIT 45$: ;REFERENCE LABEL .IF DF M$$PRO MOV $TEMP0,R0 ;WERE WE CALLED FROM DRQIO BEQ 46$ ;IF EQ NO MOV R0,SP ;RESET STACK POINTER TST (SP)+ ;ADVANCE PAST SECONDARY PACKET PTR MOV (SP)+,R4 ;SET ADDRESS OF I/O PACKET IN R4 INC R4 ;MAKE IT ODD TO INDICATE PACKET ADDRESS TST (SP)+ ;CLEAN STACK BR 461$ ;AND FORK TO CORRECT PROCESSOR 46$: MOV $TKTCB,R4 ;GET CURRENT TASK TCB ADDRESS 461$: MOV U.SCB(R5),R2 ;GET SCB ADDRESS MOV #465$,R3 ;GET THE ROUTINE ADDRESS JMP $EXRP1 ;TRANSFER EXECUTION TO CORRECT PROCESSOR 465$: BIT #1,R4 ;WERE WE CALLED FROM DRQIO ? BEQ 462$ ;IF EQ NO, JUST CALL DRIVER MOV R4,R3 ;COPY PACKET ADDRESS DEC R3 ;CLEAR LOW ORDER BIT CLR R1 ;SET LENGTH AND MOV #IS.SUC&377,R0 ;STATUS FOR $IOFIN MOV I.TCB(R3),-(SP) ;SAVE TCB ADDRESS FOR DRIVER CALL CALL $IOFIN ;FINISH THE I/O REQUEST MOV (SP)+,R4 ;RETRIEVE TCB ADDRESS 462$: MOV R4,R1 ;RESTORE CURRENT TASK TCB MOV U.SCB(R5),R4 ;RESTORE SCB ADDRESS .ENDC MOV S.PKT(R4),R0 ;GET ADDRESS OF CURRENT I/O PACKET MOV (R5),R2 ;RETRIEVE ADDRESS OF DEVICE CONTROL BLOCK MOV KINAR5,-(SP) ;SAVE KERNEL INSTR ADDR REG 5 .IF DF K$$DAS MOV KDSAR5,-(SP) ;SAVE KERNEL DATA ADDR REG 5 .IFTF .IF DF X$$HDR MOV KISAR6,-(SP) ;SAVE KERNEL APR 6 .ENDC MOV D.PCB(R2),R3 ;GET DRIVER PCB ADDRESS BEQ 47$ ;IF EQ DRIVER IS PART OF EXEC MOV P.REL(R3),KINAR5 ;MAP THE DRIVER IN INSTR SPACE .IFT MOV P.REL(R3),KDSAR5 ;MAP THE DRIVER IN DATA SPACE .IFTF 47$: MOV D.DSP(R2),R2 ;GET ADDRESS OF DRIVER DISPATCH TABLE BEQ 49$ ;IF EQ DRIVER IS UNLOADED MOV S.KRB(R4),R3 ;GET KRB ADDRESS BEQ 48$ ;IF EQ NO KRB ADDRESS MTPS K.PRI(R3) ;SET DEVICE PRIORITY MOVB K.CON(R3),R3 ;GET CONTROLLER INDEX FROM KRB ; ; CALL DRIVER AT CANCEL I/O OPERATION ENTRY POINT WITH THE ARGUMENTS: ; ; R0=ADDRESS OF THE CURRENT I/O PACKET. ; R1=ADDRESS OF THE TCB OF THE CURRENT TASK. ; R3=CONTROLLER INDEX. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UNIT CONTROL BLOCK. ; ; IF S.KRB=0 THEN R3 IS UNDEFINED AND PRIORITY =0. ; 48$: MOV R5,-(SP) ;;;PROTECT R5 FROM DRIVER CALL @D.VCAN(R2) ;;;CANCEL CURRENT REQUESTS MOV (SP)+,R5 ;;;RETRIEVE R5 MTPS #0 ;;;ALLOW DEVICE INTERRUPTS 49$: ;REF LABEL .IF DF X$$HDR MOV (SP)+,KISAR6 ;RESTORE KERNEL APR 6 .ENDC .IFT MOV (SP)+,KDSAR5 ;RESTORE KERNEL DATA ADDR REG 5 .ENDC MOV (SP)+,KINAR5 ;RESTORE KERNEL INSTR ADDR REG 5 50$: RETURN ; ;+ ; **-$SCDVT-SCAN DEVICE TABLES ; **-$SCDV1-SCAN DEVICE TABLES (ALTERNATE ENTRY) ; ; THIS ROUTINE IS A CO-ROUTINE THAT IS CALLED TO SCAN THE DEVICE TABLES. FOR EAC ; UNIT CONTROL BLOCK THE CALLER IS RECALLED. ; ; INPUTS: ; ; R3=LIST POINTER (IF ENTRY AT $SCDV1) ; ; OUTPUTS: ; ; C=1 IF NO MORE ENTRIES EXIST IN THE DEVICE TABLES. ; C=0 IF THE NEXT DEVICE TABLE ENTRY IS BEING RETURNED. ; R3=ADDRESS OF THE DEVICE CONTROL BLOCK. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UNIT CONTROL BLOCK. ;- ; ********************************************************* ; * * ; * > > > W A R N I N G < < < * ; * * ; * THE FOLLOWING ARE OFFSET DEFINITIONS WHICH ARE * ; * SUPPLIED EITHER BY DEFINITION IN THE EXEC (IOSUB) * ; * OR THE DUMMY STB FILE (FROM SFVC2). ANY CHANGE TO * ; * THESE DEFINITIONS MUST BE MADE IN BOTH MODULES. * ; * * ; ********************************************************* ; S$$SPA==10 ;SYMBOL TO ADD TO SP TO ABORT SCAN S$$SPC==6 ;OFFSET ON SP TO CLR TO SKIP CURRENT DCB $SCDVT::MOV #$DEVHD,R3 ;GET ADDRESS OF FIRST DCB ADDRESS $SCDV1::MOV (SP)+,R4 ;REMOVE RETURN ADDRESS FROM STACK 10$: MOV (R3),R3 ;GET ADDRESS OF NEXT DCB BEQ 30$ ;IF EQ NO MORE MOV D.UCB(R3),R5 ;POINT TO FIRST UCB BIT #DV.PSE,U.CW1(R5) ;PSEUDO DEVICE? BNE 10$ ;IF NE YES MOVB D.UNIT+1(R3),-(SP) ;CALCULATE NUMBER OF UCB'S TO SCAN SUB D.UNIT(R3),(SP) ; 20$: MOV R3,-(SP) ;SAVE DCB ADDRESS MOV R5,-(SP) ;SAVE UCB ADDRESS MOV R4,-(SP) ;SET RETURN ADDRESS MOV U.SCB(R5),R4 ;GET ADDRESS OF STATUS CONTROL BLOCK CLC ;INDICATE ENTRY CALL @(SP)+ ;CALL THE CALLER MOV (SP)+,R4 ;REMOVE RETURN ADDRESS MOV (SP)+,R5 ;RESTORE UCB ADDRESS MOV (SP)+,R3 ;RESTORE DCB ADDRESS ADD D.UCBL(R3),R5 ;POINT TO NEXT UCB DECB (SP) ;ANY MORE UCB'S TO SCAN? CMPB (SP),#-1 ; BNE 20$ ;IF NE YES TST (SP)+ ;CLEAN STACK BR 10$ ;GO AGAIN 30$: SEC ;INDICATE NO ENTRY JMP (R4) ;RETURN TO CALLER .END